├── .dockerignore ├── .gitignore ├── Globomantics.Api ├── Controllers │ └── WeatherForecastController.cs ├── Dockerfile ├── Extenstions │ ├── GlobomanticsRequestLogging.cs │ └── SwaggerExtensions.cs ├── Globomantics.Api.csproj ├── Middleware │ ├── ApiError.cs │ ├── ApiExceptionMiddleware.cs │ ├── ApiExceptionMiddlewareExtensions.cs │ └── ApiExceptionOptions.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── WeatherForecast.cs ├── appsettings.Development.json └── appsettings.json ├── Globomantics.Core ├── Authorization │ ├── CustomPolicyProvider.cs │ ├── MfaChallengeRequirement.cs │ ├── MfaChallengeRequirementHandler.cs │ ├── RequiredRightAttribute.cs │ ├── RequiresMfaChallengeAttribute.cs │ ├── RightRequirement.cs │ └── RightRequirementHandler.cs ├── Data │ ├── Company.cs │ └── CompanyMember.cs ├── Dockerfile ├── Globomantics.Core.csproj ├── Pages │ ├── AccessDenied.cshtml │ ├── AccessDenied.cshtml.cs │ ├── Error.cshtml │ ├── Error.cshtml.cs │ ├── Index.cshtml │ ├── Index.cshtml.cs │ ├── Login.cshtml │ ├── Login.cshtml.cs │ ├── Logout.cshtml │ ├── Logout.cshtml.cs │ ├── Members.cshtml │ ├── Members.cshtml.cs │ ├── OurStory.cshtml │ ├── OurStory.cshtml.cs │ ├── Privacy.cshtml │ ├── Privacy.cshtml.cs │ ├── Shared │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ └── _ValidationScriptsPartial.cshtml │ ├── TwoFactorChallenge.cshtml │ ├── TwoFactorChallenge.cshtml.cs │ ├── Weather.cshtml │ ├── Weather.cshtml.cs │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ └── launchSettings.json ├── Services │ ├── ApiClient.cs │ ├── IApiClient.cs │ └── PollyHelper.cs ├── Startup.cs ├── WeatherForecastModel.cs ├── appsettings.json └── wwwroot │ ├── css │ ├── .DS_Store │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap-theme.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── fontawesome.min.css │ ├── images │ │ ├── ui-icons_444444_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── jquery-ui.css │ ├── jquery-ui.min.css │ ├── owl.carousel.min.css │ ├── site.css │ ├── style-home.css │ ├── style-media.css │ ├── style-our-story.css │ └── style-robotics.css │ ├── favicon.ico │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 │ ├── images │ ├── Bitmap(1).png │ ├── Bitmap-footer.png │ ├── Bitmap.png │ ├── G.png │ ├── Globo-Logo-white-footer.svg │ ├── Globo-Logo-white.svg │ ├── Hero.png │ ├── avatar.svg │ ├── banner.png │ ├── banner3.png │ ├── girl.png │ ├── hero image.png │ ├── mobileBanner.png │ ├── pluralsight-white.png │ ├── sec2.jpg │ ├── sec3.jpg │ ├── shutterstock_211091626.png │ ├── shutterstock_252243790.png │ ├── shutterstock_564197512.png │ ├── shutterstock_645747736.png │ ├── shutterstock_662279290.png │ ├── shutterstock_725256820.png │ └── shutterstock_734412034.png │ └── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── counterup.min.js │ ├── fitvids.min.js │ ├── jquery-1.12.4.js │ ├── jquery-ui.js │ ├── jquery-ui.min.js │ ├── jquery.min.js │ ├── npm.js │ ├── owl.carousel.min.js │ ├── qrcode.min.js │ ├── theme.js │ └── waypoints.min.js ├── Globomantics.IdentityServer ├── Areas │ └── Identity │ │ └── Pages │ │ ├── Account │ │ ├── ConfirmEmail.cshtml │ │ ├── ConfirmEmail.cshtml.cs │ │ ├── ForgotPassword.cshtml │ │ ├── ForgotPassword.cshtml.cs │ │ ├── ForgotPasswordConfirmation.cshtml │ │ ├── ForgotPasswordConfirmation.cshtml.cs │ │ ├── Login.cshtml │ │ ├── Login.cshtml.cs │ │ ├── LoginWith2fa.cshtml │ │ ├── LoginWith2fa.cshtml.cs │ │ ├── LoginWithRecoveryCode.cshtml │ │ ├── LoginWithRecoveryCode.cshtml.cs │ │ ├── Logout.cshtml │ │ ├── Logout.cshtml.cs │ │ ├── Manage │ │ │ ├── ChangePassword.cshtml │ │ │ ├── ChangePassword.cshtml.cs │ │ │ ├── Disable2fa.cshtml │ │ │ ├── Disable2fa.cshtml.cs │ │ │ ├── EnableAuthenticator.cshtml │ │ │ ├── EnableAuthenticator.cshtml.cs │ │ │ ├── GenerateRecoveryCodes.cshtml │ │ │ ├── GenerateRecoveryCodes.cshtml.cs │ │ │ ├── Index.cshtml │ │ │ ├── Index.cshtml.cs │ │ │ ├── ManageNavPages.cs │ │ │ ├── ResetAuthenticator.cshtml │ │ │ ├── ResetAuthenticator.cshtml.cs │ │ │ ├── SetPassword.cshtml │ │ │ ├── SetPassword.cshtml.cs │ │ │ ├── ShowRecoveryCodes.cshtml │ │ │ ├── ShowRecoveryCodes.cshtml.cs │ │ │ ├── TwoFactorAuthentication.cshtml │ │ │ ├── TwoFactorAuthentication.cshtml.cs │ │ │ ├── _Layout.cshtml │ │ │ ├── _ManageNav.cshtml │ │ │ ├── _StatusMessage.cshtml │ │ │ └── _ViewImports.cshtml │ │ ├── Register.cshtml │ │ ├── Register.cshtml.cs │ │ ├── RegisterConfirmation.cshtml │ │ ├── RegisterConfirmation.cshtml.cs │ │ ├── ResetPassword.cshtml │ │ ├── ResetPassword.cshtml.cs │ │ ├── ResetPasswordConfirmation.cshtml │ │ ├── ResetPasswordConfirmation.cshtml.cs │ │ ├── _StatusMessage.cshtml │ │ └── _ViewImports.cshtml │ │ ├── _ValidationScriptsPartial.cshtml │ │ ├── _ViewImports.cshtml │ │ └── _ViewStart.cshtml ├── Controllers │ ├── Account │ │ ├── AccountController.cs │ │ ├── AccountOptions.cs │ │ ├── ExternalController.cs │ │ ├── ExternalProvider.cs │ │ ├── LoggedOutViewModel.cs │ │ ├── LoginInputModel.cs │ │ ├── LoginViewModel.cs │ │ ├── LogoutInputModel.cs │ │ ├── LogoutViewModel.cs │ │ └── RedirectViewModel.cs │ ├── Consent │ │ ├── ConsentController.cs │ │ ├── ConsentInputModel.cs │ │ ├── ConsentOptions.cs │ │ ├── ConsentViewModel.cs │ │ ├── ProcessConsentResult.cs │ │ └── ScopeViewModel.cs │ ├── Device │ │ ├── DeviceAuthorizationInputModel.cs │ │ ├── DeviceAuthorizationViewModel.cs │ │ └── DeviceController.cs │ ├── Diagnostics │ │ ├── DiagnosticsController.cs │ │ └── DiagnosticsViewModel.cs │ ├── Extensions.cs │ ├── Grants │ │ ├── GrantsController.cs │ │ └── GrantsViewModel.cs │ ├── Home │ │ ├── ErrorViewModel.cs │ │ └── HomeController.cs │ └── SecurityHeadersAttribute.cs ├── Data │ ├── Company.cs │ └── CompanyMember.cs ├── Dockerfile ├── Globomantics.IdentityServer.csproj ├── Identity │ ├── CustomIdentityOptions.cs │ ├── CustomPasswordHasher.cs │ ├── CustomPasswordValidator.cs │ ├── CustomUser.cs │ ├── CustomUserManager.cs │ ├── CustomUserStore-ClaimsAndRoles.cs │ ├── CustomUserStore-Lockout.cs │ ├── CustomUserStore-TwoFactor.cs │ ├── CustomUserStore.cs │ └── CustomUserValidator.cs ├── Initialization │ ├── InitialConfiguration.cs │ ├── MigrationHelper.cs │ └── Migrations │ │ └── IdentityServer │ │ ├── ConfigurationDb │ │ ├── 20201103152410_InitialMigration.Designer.cs │ │ ├── 20201103152410_InitialMigration.cs │ │ └── ConfigurationDbContextModelSnapshot.cs │ │ └── PersistedGrantDb │ │ ├── 20201103152457_InitialMigration.Designer.cs │ │ ├── 20201103152457_InitialMigration.cs │ │ └── PersistedGrantDbContextModelSnapshot.cs ├── Pages │ ├── Error.cshtml │ ├── Error.cshtml.cs │ ├── Shared │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ └── _ValidationScriptsPartial.cshtml │ ├── TwoFactorChallenge.cshtml │ ├── TwoFactorChallenge.cshtml.cs │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ └── launchSettings.json ├── Services │ └── EmailSender.cs ├── Startup.cs ├── Views │ ├── Account │ │ ├── AccessDenied.cshtml │ │ ├── LoggedOut.cshtml │ │ ├── Login.cshtml │ │ └── Logout.cshtml │ ├── Consent │ │ └── Index.cshtml │ ├── Device │ │ ├── Success.cshtml │ │ ├── UserCodeCapture.cshtml │ │ └── UserCodeConfirmation.cshtml │ ├── Diagnostics │ │ └── Index.cshtml │ ├── Grants │ │ └── Index.cshtml │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── Redirect.cshtml │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ ├── _Nav.cshtml │ │ ├── _ScopeListItem.cshtml │ │ └── _ValidationSummary.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── appsettings.json ├── tempkey.jwk └── wwwroot │ ├── css │ ├── .DS_Store │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap-theme.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── fontawesome.min.css │ ├── images │ │ ├── ui-icons_444444_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── jquery-ui.css │ ├── jquery-ui.min.css │ ├── owl.carousel.min.css │ ├── site.css │ ├── style-home.css │ ├── style-media.css │ ├── style-our-story.css │ └── style-robotics.css │ ├── favicon.ico │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 │ ├── images │ ├── Bitmap(1).png │ ├── Bitmap-footer.png │ ├── Bitmap.png │ ├── G.png │ ├── Globo-Logo-white-footer.svg │ ├── Globo-Logo-white.svg │ ├── Hero.png │ ├── avatar.svg │ ├── banner.png │ ├── banner3.png │ ├── girl.png │ ├── hero image.png │ ├── mobileBanner.png │ ├── pluralsight-white.png │ ├── sec2.jpg │ ├── sec3.jpg │ ├── shutterstock_211091626.png │ ├── shutterstock_252243790.png │ ├── shutterstock_564197512.png │ ├── shutterstock_645747736.png │ ├── shutterstock_662279290.png │ ├── shutterstock_725256820.png │ └── shutterstock_734412034.png │ ├── js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── counterup.min.js │ ├── fitvids.min.js │ ├── jquery-1.12.4.js │ ├── jquery-ui.js │ ├── jquery-ui.min.js │ ├── jquery.min.js │ ├── npm.js │ ├── owl.carousel.min.js │ ├── qrcode.min.js │ ├── site.js │ ├── theme.js │ └── waypoints.min.js │ └── lib │ ├── bootstrap │ ├── LICENSE │ └── dist │ │ ├── css │ │ ├── bootstrap-grid.css │ │ ├── bootstrap-grid.css.map │ │ ├── bootstrap-grid.min.css │ │ ├── bootstrap-grid.min.css.map │ │ ├── bootstrap-reboot.css │ │ ├── bootstrap-reboot.css.map │ │ ├── bootstrap-reboot.min.css │ │ ├── bootstrap-reboot.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ │ └── js │ │ ├── bootstrap.bundle.js │ │ ├── bootstrap.bundle.js.map │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ ├── bootstrap.js │ │ ├── bootstrap.js.map │ │ ├── bootstrap.min.js │ │ └── bootstrap.min.js.map │ ├── jquery-validation-unobtrusive │ ├── LICENSE.txt │ ├── jquery.validate.unobtrusive.js │ └── jquery.validate.unobtrusive.min.js │ ├── jquery-validation │ ├── LICENSE.md │ └── dist │ │ ├── additional-methods.js │ │ ├── additional-methods.min.js │ │ ├── jquery.validate.js │ │ └── jquery.validate.min.js │ └── jquery │ ├── LICENSE.txt │ └── dist │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map ├── Globomantics.sln ├── README.md ├── docker-compose.dcproj ├── docker-compose.yml ├── k8s ├── globo-ingress.yml ├── globois4.configmap.yml ├── globois4.yml ├── globoseq-initial.yml ├── globoseq.yml ├── globosmtp-initial.yml ├── globosmtp.yml ├── globosql.yml ├── id-local.conf ├── id-local.crt ├── id-local.key └── id-local.pfx ├── nginx ├── id-local.conf ├── id-local.crt ├── id-local.key ├── id-local.pfx ├── nginx.Dockerfile ├── nginx.local.conf ├── www-local.conf ├── www-local.crt ├── www-local.key └── www-local.pfx └── sql ├── InitializeGlobomanticsDb.sql ├── entrypoint.sh ├── setup.sh ├── sql.Dockerfile └── wait-for-it.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /.vs 6 | */bin 7 | */obj 8 | *.user 9 | */.vs 10 | /packages 11 | /bin/Debug 12 | /obj 13 | -------------------------------------------------------------------------------- /Globomantics.Api/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Globomantics.Api.Controllers 8 | { 9 | [ApiController] 10 | [ApiVersion("1.0")] 11 | [Route("v{version:apiVersion}/[controller]")] 12 | public class WeatherForecastController : ControllerBase 13 | { 14 | private static readonly string[] Summaries = new[] 15 | { 16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 17 | }; 18 | 19 | private readonly ILogger _logger; 20 | 21 | public WeatherForecastController(ILogger logger) 22 | { 23 | _logger = logger; 24 | } 25 | 26 | [HttpGet] 27 | public IEnumerable Get() 28 | { 29 | var rng = new Random(); 30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 31 | { 32 | Date = DateTime.Now.AddDays(index), 33 | TemperatureC = rng.Next(-20, 55), 34 | Summary = Summaries[rng.Next(Summaries.Length)] 35 | }) 36 | .ToArray(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Globomantics.Api/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base 4 | WORKDIR /app 5 | COPY nginx/id-local.crt /usr/local/share/ca-certificates/id-local.crt 6 | RUN update-ca-certificates 7 | EXPOSE 80 8 | EXPOSE 443 9 | 10 | FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build 11 | WORKDIR /src 12 | COPY ["Globomantics.Api/Globomantics.Api.csproj", "Globomantics.Api/"] 13 | RUN dotnet restore "Globomantics.Api/Globomantics.Api.csproj" 14 | COPY . . 15 | WORKDIR "/src/Globomantics.Api" 16 | RUN dotnet build "Globomantics.Api.csproj" -c Release -o /app/build 17 | 18 | FROM build AS publish 19 | RUN dotnet publish "Globomantics.Api.csproj" -c Release -o /app/publish 20 | 21 | FROM base AS final 22 | WORKDIR /app 23 | COPY --from=publish /app/publish . 24 | ENTRYPOINT ["dotnet", "Globomantics.Api.dll"] -------------------------------------------------------------------------------- /Globomantics.Api/Extenstions/GlobomanticsRequestLogging.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Security.Claims; 4 | using IdentityModel; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Http; 7 | using Serilog; 8 | using Serilog.Events; 9 | 10 | namespace Globomantics.Api.Extenstions 11 | { 12 | public static class GlobomanticsRequestLogging 13 | { 14 | 15 | public static IApplicationBuilder UseGlobomanticsStyleRequestLogging(this IApplicationBuilder app) 16 | { 17 | return app.UseSerilogRequestLogging(options => 18 | { 19 | options.GetLevel = ExcludeHealthChecks; 20 | options.EnrichDiagnosticContext = (diagnosticContext, httpContext) => 21 | { 22 | diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value); 23 | diagnosticContext.Set("UserAgent", httpContext.Request.Headers["User-Agent"]); 24 | var user = httpContext.User.Identity; 25 | if (user != null && user.IsAuthenticated) 26 | { 27 | var ci = user as ClaimsIdentity; 28 | var email = ci?.Claims.FirstOrDefault(a => a.Type == "email")?.Value; 29 | diagnosticContext.Set("UserName", email); 30 | diagnosticContext.Set("UserId",ci?.FindFirst(JwtClaimTypes.Subject)?.Value); 31 | } 32 | }; 33 | }); 34 | 35 | } 36 | 37 | private static LogEventLevel ExcludeHealthChecks(HttpContext ctx, double _, Exception ex) => 38 | ex != null 39 | ? LogEventLevel.Error 40 | : ctx.Response.StatusCode > 499 41 | ? LogEventLevel.Error 42 | : IsHealthCheckEndpoint(ctx) // Not an error, check if it was a health check 43 | ? LogEventLevel.Verbose // Was a health check, use Verbose 44 | : LogEventLevel.Information; 45 | 46 | private static bool IsHealthCheckEndpoint(HttpContext ctx) 47 | { 48 | var endpoint = ctx.GetEndpoint(); 49 | if (endpoint != null) 50 | { 51 | return string.Equals(endpoint.DisplayName, "Health checks", StringComparison.Ordinal); 52 | } 53 | return false; // No endpoint, so not a health check endpoint 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Globomantics.Api/Globomantics.Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | ce1b2d59-a082-4a96-afdc-852260bb3513 6 | Linux 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Globomantics.Api/Middleware/ApiError.cs: -------------------------------------------------------------------------------- 1 | namespace Globomantics.Api.Middleware 2 | { 3 | public class ApiError 4 | { 5 | public string Id { get; internal set; } 6 | public short Status { get; internal set; } 7 | public string Code { get; set; } 8 | public string Links { get; set; } 9 | public string Title { get; internal set; } 10 | public string Detail { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Globomantics.Api/Middleware/ApiExceptionMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Http; 5 | using Newtonsoft.Json; 6 | using Serilog; 7 | 8 | namespace Globomantics.Api.Middleware 9 | { 10 | public class ApiExceptionMiddleware 11 | { 12 | private readonly RequestDelegate _next; 13 | private readonly ApiExceptionOptions _options; 14 | 15 | public ApiExceptionMiddleware(ApiExceptionOptions options, RequestDelegate next) 16 | { 17 | _next = next; 18 | _options = options; 19 | } 20 | 21 | public async Task Invoke(HttpContext context /* other dependencies */) 22 | { 23 | try 24 | { 25 | await _next(context); 26 | } 27 | catch (Exception ex) 28 | { 29 | await HandleExceptionAsync(context, ex, _options); 30 | } 31 | } 32 | 33 | private static Task HandleExceptionAsync(HttpContext context, Exception exception, ApiExceptionOptions opts) 34 | { 35 | var error = new ApiError 36 | { 37 | Id = Guid.NewGuid().ToString(), 38 | Status = (short) HttpStatusCode.InternalServerError, 39 | Title = "Some kind of error occurred in the API. Please use the id and contact our support team if the problem persists." 40 | }; 41 | 42 | opts.AddResponseDetails?.Invoke(context, exception, error); 43 | 44 | Log.ForContext("ErrorId", error.Id) 45 | .Error(exception, "An exception was caught in the API request pipeline"); 46 | 47 | var result = JsonConvert.SerializeObject(error); 48 | context.Response.ContentType = "application/json"; 49 | context.Response.StatusCode = (int) HttpStatusCode.InternalServerError; 50 | return context.Response.WriteAsync(result); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Globomantics.Api/Middleware/ApiExceptionMiddlewareExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | 4 | namespace Globomantics.Api.Middleware 5 | { 6 | public static class ApiExceptionMiddlewareExtensions 7 | { 8 | public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder, 9 | Action configureOptions) 10 | { 11 | var options = new ApiExceptionOptions(); 12 | configureOptions(options); 13 | 14 | return builder.UseMiddleware(options); 15 | } 16 | public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder) 17 | { 18 | var options = new ApiExceptionOptions(); 19 | return builder.UseMiddleware(options); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Globomantics.Api/Middleware/ApiExceptionOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace Globomantics.Api.Middleware 5 | { 6 | public class ApiExceptionOptions 7 | { 8 | public Action AddResponseDetails { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Globomantics.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | using Serilog; 4 | 5 | namespace Globomantics.Api 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateHostBuilder(args).Build().Run(); 12 | Log.CloseAndFlush(); 13 | } 14 | 15 | public static IHostBuilder CreateHostBuilder(string[] args) => 16 | Host.CreateDefaultBuilder(args) 17 | .UseSerilog((context, provider, loggerConfiguration) => 18 | { 19 | loggerConfiguration 20 | .ReadFrom.Configuration(context.Configuration) 21 | .Enrich.FromLogContext() 22 | .WriteTo.Console() 23 | .WriteTo.Seq("http://globoseq:5341"); ; 24 | }) 25 | .ConfigureWebHostDefaults(webBuilder => 26 | { 27 | webBuilder.UseStartup(); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Globomantics.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "https://localhost:44376/", 7 | "sslPort": 44376 8 | } 9 | }, 10 | "$schema": "http://json.schemastore.org/launchsettings.json", 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "https://localhost:44376/", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "Globomantics.Api": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "weatherforecast", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | }, 27 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 28 | }, 29 | "Docker": { 30 | "commandName": "Docker", 31 | "launchBrowser": true, 32 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/", 33 | "publishAllPorts": true, 34 | "useSSL": true 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Globomantics.Api/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Globomantics.Api 4 | { 5 | public class WeatherForecast 6 | { 7 | public DateTime Date { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 12 | 13 | public string Summary { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Globomantics.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Globomantics.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "AuthN": { 3 | "Authority": "https://id-local.globomantics.com:44395", 4 | "SwaggerClientId": "globo-swagger", 5 | "ApiName": "glob_api", 6 | "AdditionalScopes": "openid profile glob_profile" 7 | }, 8 | "Serilog": { 9 | "MinimumLevel": { 10 | "Default": "Debug", 11 | "Override": { 12 | "Microsoft": "Warning", 13 | "System": "Warning" 14 | } 15 | } 16 | }, 17 | "CORSOrigins": "*" 18 | } 19 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/CustomPolicyProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Authentication.Cookies; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace Globomantics.Core.Authorization 9 | { 10 | public class CustomPolicyProvider : IAuthorizationPolicyProvider 11 | { 12 | private DefaultAuthorizationPolicyProvider BackupPolicyProvider { get; } 13 | 14 | public CustomPolicyProvider(IOptions options) 15 | { 16 | BackupPolicyProvider = new DefaultAuthorizationPolicyProvider(options); 17 | } 18 | 19 | public Task GetPolicyAsync(string policyName) 20 | { 21 | if (policyName.StartsWith(RequiredRightAttribute.PolicyPrefix, 22 | StringComparison.OrdinalIgnoreCase)) 23 | { 24 | var policy = new AuthorizationPolicyBuilder() 25 | .AddRequirements(new 26 | RightRequirement(policyName.Substring(RequiredRightAttribute.PolicyPrefix.Length))) 27 | .Build(); 28 | 29 | return Task.FromResult(policy); 30 | } 31 | 32 | if (policyName == RequiresMfaChallengeAttribute.PolicyName) 33 | { 34 | var policy = new AuthorizationPolicyBuilder() 35 | .AddRequirements(new MfaChallengeRequirement()) 36 | .Build(); 37 | 38 | return Task.FromResult(policy); 39 | } 40 | 41 | return BackupPolicyProvider.GetPolicyAsync(policyName); 42 | } 43 | 44 | public Task GetDefaultPolicyAsync() 45 | { 46 | return Task.FromResult(new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, "oidc") 47 | .RequireAuthenticatedUser() 48 | .Build()); 49 | } 50 | 51 | public Task GetFallbackPolicyAsync() 52 | { 53 | return Task.FromResult(null); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/MfaChallengeRequirement.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace Globomantics.Core.Authorization 4 | { 5 | public class MfaChallengeRequirement : IAuthorizationRequirement 6 | { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/MfaChallengeRequirementHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text.Encodings.Web; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Routing; 8 | 9 | namespace Globomantics.Core.Authorization 10 | { 11 | public class MfaChallengeRequirementHandler : AuthorizationHandler 12 | { 13 | private readonly HttpContext _httpCtx; 14 | private readonly UrlEncoder _urlEncoder; 15 | 16 | public MfaChallengeRequirementHandler(IHttpContextAccessor httpContextAccessor, 17 | UrlEncoder urlEncoder) 18 | { 19 | _httpCtx = httpContextAccessor.HttpContext; 20 | _urlEncoder = urlEncoder; 21 | } 22 | 23 | protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 24 | MfaChallengeRequirement requirement) 25 | { 26 | var amr = context.User.Claims.FirstOrDefault(c => c.Type == "amr")?.Value; 27 | 28 | if (string.Equals(amr, "mfa")) // user signed in and was challenged 29 | { 30 | context.Succeed(requirement); 31 | return Task.CompletedTask; 32 | } 33 | 34 | var twoFactorEnabled = context.User.Claims 35 | .FirstOrDefault(c => c.Type == "MfaEnabled")?.Value; 36 | if (string.Equals(twoFactorEnabled, "true", StringComparison.InvariantCultureIgnoreCase)) 37 | { 38 | // user has two-factor enabled but may not have been challenged 39 | // cookie here is set by the twofactorchallenge page 40 | var alreadyDone = _httpCtx.Request.Cookies["MfaChallengeCompleted"]; 41 | if (!string.IsNullOrEmpty(alreadyDone)) 42 | { 43 | // user has completed a challenge during current session 44 | context.Succeed(requirement); 45 | return Task.CompletedTask; 46 | } 47 | 48 | if (context.Resource is RouteEndpoint endpoint) 49 | { 50 | var returnUrl = endpoint.DisplayName; 51 | // TODO: handle parameters here if there are any 52 | var encodedReturnUrl = _urlEncoder.Encode(returnUrl); 53 | _httpCtx.Response.Redirect($"/TwoFactorChallenge?returnUrl={encodedReturnUrl}"); 54 | context.Succeed(requirement); 55 | return Task.CompletedTask; 56 | } 57 | } 58 | 59 | context.Fail(); // user does not have mfa enabled 60 | return Task.CompletedTask; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/RequiredRightAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace Globomantics.Core.Authorization 4 | { 5 | public class RequiredRightAttribute : AuthorizeAttribute 6 | { 7 | public const string PolicyPrefix = "RequiredRight"; 8 | 9 | public RequiredRightAttribute(string right) 10 | { 11 | Right = right; 12 | } 13 | 14 | public string Right 15 | { 16 | get => Policy.Substring(PolicyPrefix.Length); 17 | set => Policy = $"{PolicyPrefix}{value}"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/RequiresMfaChallengeAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace Globomantics.Core.Authorization 4 | { 5 | public class RequiresMfaChallengeAttribute : AuthorizeAttribute 6 | { 7 | public const string PolicyName = "MfaChallengeRequirement"; 8 | 9 | public RequiresMfaChallengeAttribute() 10 | { 11 | Policy = PolicyName; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/RightRequirement.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace Globomantics.Core.Authorization 4 | { 5 | public class RightRequirement : IAuthorizationRequirement 6 | { 7 | public string Right { get; } 8 | 9 | public RightRequirement(string right) 10 | { 11 | Right = right; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Globomantics.Core/Authorization/RightRequirementHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Security.Claims; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Authorization; 6 | 7 | namespace Globomantics.Core.Authorization 8 | { 9 | public class RightRequirementHandler : AuthorizationHandler 10 | { 11 | protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, 12 | RightRequirement requirement) 13 | { 14 | var role = context.User.Claims 15 | .FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value; 16 | 17 | if (string.IsNullOrEmpty(role)) 18 | { 19 | context.Fail(); 20 | } 21 | else if (await RoleHasRight(context.User, role, requirement.Right)) 22 | { 23 | context.Succeed(requirement); 24 | } 25 | else 26 | { 27 | context.Fail(); 28 | } 29 | } 30 | 31 | private Task RoleHasRight(ClaimsPrincipal user, string role, string right) 32 | { 33 | var rightsForRoles = new Dictionary> 34 | { 35 | {"admin", new List {"ViewMembers", "UpdateMembers", "ViewProfile"}}, 36 | {"general", new List {"ViewProfile", "SeeDashboard" }} 37 | }; 38 | // this could be a cached db lookup or something based on userid, a list of roles, or whatever. 39 | return Task.FromResult( 40 | rightsForRoles.ContainsKey(role) && 41 | rightsForRoles[role].Exists(a => a == right)); 42 | 43 | // based on role , companyid, or other claims - look up requested right 44 | // return existence of right for that combo 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Globomantics.Core/Data/Company.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Globomantics.Core.Data 4 | { 5 | public class Company 6 | { 7 | public int Id { get; set; } 8 | public string Name { get; set; } 9 | public List Members { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Globomantics.Core/Data/CompanyMember.cs: -------------------------------------------------------------------------------- 1 | namespace Globomantics.Core.Data 2 | { 3 | public class CompanyMember 4 | { 5 | public int Id { get; set; } 6 | public int CompanyId { get; set; } 7 | public string MemberEmail { get; set; } 8 | public Company Company { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Globomantics.Core/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base 4 | WORKDIR /app 5 | COPY nginx/id-local.crt /usr/local/share/ca-certificates/id-local.crt 6 | COPY nginx/www-local.crt /usr/local/share/ca-certificates/www-local.crt 7 | RUN update-ca-certificates 8 | EXPOSE 80 9 | EXPOSE 443 10 | 11 | FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build 12 | WORKDIR /src 13 | COPY ["Globomantics.Core/Globomantics.Core.csproj", "Globomantics.Core/"] 14 | RUN dotnet restore "Globomantics.Core/Globomantics.Core.csproj" 15 | COPY . . 16 | WORKDIR "/src/Globomantics.Core" 17 | RUN dotnet build "Globomantics.Core.csproj" -c Release -o /app/build 18 | 19 | FROM build AS publish 20 | RUN dotnet publish "Globomantics.Core.csproj" -c Release -o /app/publish 21 | 22 | FROM base AS final 23 | WORKDIR /app 24 | COPY --from=publish /app/publish . 25 | ENTRYPOINT ["dotnet", "Globomantics.Core.dll"] -------------------------------------------------------------------------------- /Globomantics.Core/Globomantics.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | 84e0b4b7-930c-48fc-8118-4709f42f962c 6 | Linux 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | all 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/AccessDenied.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.AccessDeniedModel 3 | @{ 4 | } 5 | 6 |

Access Denied!!

7 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/AccessDenied.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace Globomantics.Core.Pages 5 | { 6 | [AllowAnonymous] 7 | public class AccessDeniedModel : PageModel 8 | { 9 | public void OnGet() 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to the Development environment displays detailed information about the error that occurred. 20 |

21 |

22 | The Development environment shouldn't be enabled for deployed applications. 23 | It can result in displaying sensitive information from exceptions to end users. 24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 25 | and restarting the app. 26 |

27 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Globomantics.Core.Pages 7 | { 8 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 9 | public class ErrorModel : PageModel 10 | { 11 | public string RequestId { get; set; } 12 | 13 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 14 | 15 | private readonly ILogger _logger; 16 | 17 | public ErrorModel(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | public void OnGet() 23 | { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | @{ 4 | ViewData["Title"] = "Home page"; 5 | } 6 | 7 | 27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 | 35 |

DARK ENERGY

36 |

BRIGHTENS THE WORLD

37 | Public Adjuster 38 | 39 |
40 | Learn More 41 |
42 |
43 |
44 |

ROBOTICS

45 |

THEY ARE HERE AND THEY PLAY

46 | Public 47 |
48 | Learn More 49 |
50 | 51 |
52 |
53 |

STRANGERS RISE

54 |

ASCENSION GOES TECHNICAL

55 | Public 56 |
57 | Learn More 58 | 59 |
60 | 61 |
62 |
63 |
64 |
65 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace Globomantics.Core.Pages 6 | { 7 | [AllowAnonymous] 8 | public class IndexModel : PageModel 9 | { 10 | private readonly ILogger _logger; 11 | 12 | public IndexModel(ILogger logger) 13 | { 14 | _logger = logger; 15 | } 16 | 17 | public void OnGet() 18 | { 19 | 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Login.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.LoginModel 3 | @{ 4 | } 5 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Login.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace Globomantics.Core.Pages 5 | { 6 | public class LoginModel : PageModel 7 | { 8 | public IActionResult OnGet() 9 | { 10 | return LocalRedirect("/"); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.LogoutModel 3 | @{ 4 | } 5 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.Cookies; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | 5 | namespace Globomantics.Core.Pages 6 | { 7 | public class LogoutModel : PageModel 8 | { 9 | public IActionResult OnGet() 10 | { 11 | return SignOut(CookieAuthenticationDefaults.AuthenticationScheme, "oidc"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Members.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.MembersModel 3 | @{ 4 | } 5 | 6 |
7 |
8 |

@Model.Company.Name

9 |
    10 | @foreach (var member in Model.Company.Members) 11 | { 12 |
  • @member.MemberEmail
  • 13 | } 14 |
15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Members.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Linq; 4 | using Dapper; 5 | using Globomantics.Core.Data; 6 | using Microsoft.AspNetCore.Authorization; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | namespace Globomantics.Core.Pages 10 | { 11 | [Authorize(Roles = "admin")] 12 | //[Authorize(Policy = "MfaRequired")] 13 | //[RequiredRight("ViewMembers")] 14 | //[RequiresMfaChallenge] 15 | public class MembersModel : PageModel 16 | { 17 | private readonly IDbConnection _db; 18 | public Company Company { get; set; } 19 | 20 | public MembersModel(IDbConnection db) 21 | { 22 | _db = db; 23 | } 24 | 25 | public void OnGet() 26 | { 27 | var companyId = User.Claims 28 | .FirstOrDefault(c => c.Type == "CompanyId")?.Value; 29 | 30 | var compDict = new Dictionary(); 31 | var sql = @" 32 | SELECT * 33 | FROM dbo.Companies c 34 | JOIN dbo.CompanyMembers cm 35 | ON c.Id = cm.CompanyId 36 | WHERE c.Id = @CompanyId"; 37 | 38 | Company = _db.Query(sql, (c, cm) => 39 | { 40 | if (!compDict.TryGetValue(c.Id, out var currComp)) 41 | { 42 | currComp = c; 43 | currComp.Members = new List(); 44 | compDict.Add(currComp.Id, currComp); 45 | } 46 | currComp.Members.Add(cm); 47 | return currComp; 48 | 49 | }, new {companyId}).FirstOrDefault(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/OurStory.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.RazorPages; 2 | 3 | namespace Globomantics.Core.Pages 4 | { 5 | public class OurStoryModel : PageModel 6 | { 7 | public void OnGet() 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Privacy.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model PrivacyModel 3 | @{ 4 | ViewData["Title"] = "Privacy Policy"; 5 | } 6 |

@ViewData["Title"]

7 | 8 |

Use this page to detail your site's privacy policy.

9 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Privacy.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.RazorPages; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Globomantics.Core.Pages 5 | { 6 | public class PrivacyModel : PageModel 7 | { 8 | private readonly ILogger _logger; 9 | 10 | public PrivacyModel(ILogger logger) 11 | { 12 | _logger = logger; 13 | } 14 | 15 | public void OnGet() 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 |  26 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/TwoFactorChallenge.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.TwoFactorChallengeModel 3 | @{ 4 | } 5 | 6 |

@ViewData["Title"]

7 |
8 |

To access the requested feature you will need to verify via authentication:

9 |
10 |
11 |
12 |
13 | 14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 |
22 | 23 |
24 | 25 | @section Scripts { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Weather.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.WeatherModel 3 | 4 |

Weather!

5 | 6 | @if (Model.Forecast != null) 7 | { 8 |
    9 | @foreach (var day in Model.Forecast) 10 | { 11 |
  • @day.Date.ToShortDateString() -- @day.Summary -- @day.TemperatureC -- @day.TemperatureF
  • 12 | } 13 |
14 | } -------------------------------------------------------------------------------- /Globomantics.Core/Pages/Weather.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using Globomantics.Core.Services; 4 | using Microsoft.AspNetCore.Mvc.RazorPages; 5 | 6 | namespace Globomantics.Core.Pages 7 | { 8 | public class WeatherModel : PageModel 9 | { 10 | private readonly IApiClient _apiClient; 11 | public List Forecast { get; set; } 12 | 13 | public WeatherModel(IApiClient apiClient) 14 | { 15 | _apiClient = apiClient; 16 | } 17 | 18 | public async Task OnGet() 19 | { 20 | Forecast = await _apiClient.GetWeatherForecastAsync(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @namespace Globomantics.Core.Pages 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /Globomantics.Core/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Globomantics.Core/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | using Serilog; 4 | 5 | namespace Globomantics.Core 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateHostBuilder(args).Build().Run(); 12 | Log.CloseAndFlush(); 13 | } 14 | 15 | public static IHostBuilder CreateHostBuilder(string[] args) => 16 | Host.CreateDefaultBuilder(args) 17 | .UseSerilog((context, provider, loggerConfiguration) => 18 | { 19 | loggerConfiguration 20 | .ReadFrom.Configuration(context.Configuration) 21 | .Enrich.FromLogContext() 22 | .WriteTo.Console() 23 | .WriteTo.Seq("http://globoseq"); ; 24 | }) 25 | .ConfigureWebHostDefaults(webBuilder => 26 | { 27 | webBuilder.UseStartup(); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Globomantics.Core/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "https://localhost:44320/", 7 | "sslPort": 44320 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "https://localhost:44320/", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "WebApplication1": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | }, 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 26 | }, 27 | "Docker": { 28 | "commandName": "Docker", 29 | "launchBrowser": true, 30 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/", 31 | "publishAllPorts": true, 32 | "useSSL": true 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Globomantics.Core/Services/ApiClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.Http; 4 | using System.Net.Http.Json; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Configuration; 7 | 8 | namespace Globomantics.Core.Services 9 | { 10 | public class ApiClient : IApiClient 11 | { 12 | private readonly HttpClient _cli; 13 | 14 | public ApiClient(HttpClient cli, IConfiguration config) 15 | { 16 | _cli = cli; 17 | _cli.BaseAddress = new Uri(config.GetValue("ApiBaseUrl")); 18 | } 19 | 20 | public async Task> GetWeatherForecastAsync() 21 | { 22 | return await _cli.GetFromJsonAsync>("v1/weatherforecast"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Globomantics.Core/Services/IApiClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace Globomantics.Core.Services 5 | { 6 | public interface IApiClient 7 | { 8 | Task> GetWeatherForecastAsync(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Globomantics.Core/Services/PollyHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Polly; 5 | using Polly.Extensions.Http; 6 | using Polly.Timeout; 7 | using Serilog; 8 | 9 | namespace Globomantics.Core.Services 10 | { 11 | public static class PollyHelpers 12 | { 13 | public static IHttpClientBuilder AddResiliencePolicies(this IHttpClientBuilder httpClientBuilder) 14 | { 15 | var timesToRetry = 10; 16 | var secondsToWaitForSingleResponse = 10; 17 | // this will handle transient errors (500 errros, 408 and httprequestexceptions) by delaying 18 | // and then retrying based on the array below 19 | 20 | var jitterer = new Random(); 21 | var retryPolicy = HttpPolicyExtensions 22 | .HandleTransientHttpError() 23 | .Or() 24 | .WaitAndRetryAsync( 25 | retryCount: timesToRetry, 26 | sleepDurationProvider: retryAttempt => 27 | (TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) // exponential back-off: 2, 4, 8 etc 28 | + TimeSpan.FromMilliseconds(jitterer.Next(0, 1000))), 29 | onRetry: (result, timeSpan, retryAttempt, ctx) => 30 | { 31 | Log 32 | .ForContext("RequestUri", result.Result.RequestMessage.RequestUri) 33 | .ForContext("ResponseCode", result.Result.StatusCode) 34 | .Information(result.Exception, $"Retrying HTTP call -- ({retryAttempt} of {timesToRetry})"); 35 | }); // plus some jitter: up to 1 second); 36 | 37 | // This will kill / fail an api call if it takes longer than specified seconds to receive response 38 | var timeoutPolicy = Policy.TimeoutAsync(secondsToWaitForSingleResponse); 39 | 40 | return httpClientBuilder 41 | .AddPolicyHandler(retryPolicy) 42 | .AddPolicyHandler(timeoutPolicy); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Globomantics.Core/WeatherForecastModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Globomantics.Core 4 | { 5 | public class WeatherForecastModel 6 | { 7 | public DateTime Date { get; set; } 8 | public int TemperatureC { get; set; } 9 | public int TemperatureF { get; set; } 10 | public string Summary { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Globomantics.Core/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "GlobomanticsDb": "Server=globosql;Database=Globomantics;User Id=globo_dbuser;Password=SqlonLinux?!;MultipleActiveResultSets=true" 4 | }, 5 | "AuthN": { 6 | "Authority": "https://id-local.globomantics.com:44395", 7 | "ClientId": "globo-core", 8 | "ClientSecret": "secret", 9 | "Scopes": "openid profile glob_profile glob_api offline_access" 10 | }, 11 | "ApiBaseUrl": "https://www-local.globomantics.com:44395/api/", 12 | "Serilog": { 13 | "MinimumLevel": { 14 | "Default": "Debug", 15 | "Override": { 16 | "Microsoft": "Warning", 17 | "System": "Warning" 18 | } 19 | } 20 | }, 21 | "AllowedHosts": "*" 22 | } -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/css/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/css/.DS_Store -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/css/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/css/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | /* Provide sufficient contrast against white background */ 11 | a { 12 | color: #0366d6; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 22 | color: #fff; 23 | background-color: #1b6ec2; 24 | border-color: #1861ac; 25 | } 26 | 27 | /* Sticky footer styles 28 | -------------------------------------------------- */ 29 | html { 30 | font-size: 14px; 31 | } 32 | @media (min-width: 768px) { 33 | html { 34 | font-size: 16px; 35 | } 36 | } 37 | 38 | .border-top { 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | .border-bottom { 42 | border-bottom: 1px solid #e5e5e5; 43 | } 44 | 45 | .box-shadow { 46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 47 | } 48 | 49 | button.accept-policy { 50 | font-size: 1rem; 51 | line-height: inherit; 52 | } 53 | 54 | /* Sticky footer styles 55 | -------------------------------------------------- */ 56 | html { 57 | position: relative; 58 | min-height: 100%; 59 | } 60 | 61 | body { 62 | /* Margin bottom by footer height */ 63 | margin-bottom: 60px; 64 | } 65 | .footer { 66 | position: absolute; 67 | bottom: 0; 68 | width: 100%; 69 | white-space: nowrap; 70 | line-height: 60px; /* Vertically center the text there */ 71 | } 72 | -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/Bitmap(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/Bitmap(1).png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/Bitmap-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/Bitmap-footer.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/Bitmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/Bitmap.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/G.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/G.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/Hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/Hero.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/avatar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1F396E79-704A-4B98-A5D9-46E8C401B934 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/banner.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/banner3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/banner3.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/girl.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/hero image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/hero image.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/mobileBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/mobileBanner.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/pluralsight-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/pluralsight-white.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/sec2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/sec2.jpg -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/sec3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/sec3.jpg -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_211091626.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_211091626.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_252243790.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_252243790.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_564197512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_564197512.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_645747736.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_645747736.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_662279290.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_662279290.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_725256820.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_725256820.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/images/shutterstock_734412034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.Core/wwwroot/images/shutterstock_734412034.png -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/js/counterup.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery.counterup.js 1.0 3 | * 4 | * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 5 | * Released under the GPL v2 License 6 | * 7 | * Date: Nov 26, 2013 8 | */(function(e){"use strict";e.fn.counterUp=function(t){var n=e.extend({time:400,delay:10},t);return this.each(function(){var t=e(this),r=n,i=function(){var e=[],n=r.time/r.delay,i=t.text(),s=/[0-9]+,[0-9]+/.test(i);i=i.replace(/,/g,"");var o=/^[0-9]+$/.test(i),u=/^[0-9]+\.[0-9]+$/.test(i),a=u?(i.split(".")[1]||[]).length:0;for(var f=n;f>=1;f--){var l=parseInt(i/n*f);u&&(l=parseFloat(i/n*f).toFixed(a));if(s)while(/(\d+)(\d{3})/.test(l.toString()))l=l.toString().replace(/(\d+)(\d{3})/,"$1,$2");e.unshift(l)}t.data("counterup-nums",e);t.text("0");var c=function(){t.text(t.data("counterup-nums").shift());if(t.data("counterup-nums").length)setTimeout(t.data("counterup-func"),r.delay);else{delete t.data("counterup-nums");t.data("counterup-nums",null);t.data("counterup-func",null)}};t.data("counterup-func",c);setTimeout(t.data("counterup-func"),r.delay)};t.waypoint(i,{offset:"100%",triggerOnce:!0})})}})(jQuery); -------------------------------------------------------------------------------- /Globomantics.Core/wwwroot/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ConfirmEmailModel 3 | @{ 4 | ViewData["Title"] = "Confirm email"; 5 | } 6 | 7 |

@ViewData["Title"]

8 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ConfirmEmail.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Threading.Tasks; 3 | using Globomantics.IdentityServer.Identity; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Identity; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.AspNetCore.WebUtilities; 9 | 10 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account 11 | { 12 | [AllowAnonymous] 13 | public class ConfirmEmailModel : PageModel 14 | { 15 | private readonly UserManager _userManager; 16 | 17 | public ConfirmEmailModel(UserManager userManager) 18 | { 19 | _userManager = userManager; 20 | } 21 | 22 | [TempData] 23 | public string StatusMessage { get; set; } 24 | 25 | public async Task OnGetAsync(string userId, string code) 26 | { 27 | if (userId == null || code == null) 28 | { 29 | return RedirectToPage("/Index"); 30 | } 31 | 32 | var user = await _userManager.FindByIdAsync(userId); 33 | if (user == null) 34 | { 35 | return NotFound($"Unable to load user with ID '{userId}'."); 36 | } 37 | 38 | code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); 39 | var result = await _userManager.ConfirmEmailAsync(user, code); 40 | StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; 41 | return Page(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ForgotPasswordModel 3 | @{ 4 | ViewData["Title"] = "Forgot your password?"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |

Enter your email.

9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 | 24 | @section Scripts { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ForgotPasswordConfirmation 3 | @{ 4 | ViewData["Title"] = "Forgot password confirmation"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |

9 | Please check your email to reset your password. 10 |

11 | 12 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ForgotPasswordConfirmation.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account 5 | { 6 | [AllowAnonymous] 7 | public class ForgotPasswordConfirmation : PageModel 8 | { 9 | public void OnGet() 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/LoginWith2fa.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LoginWith2faModel 3 | @{ 4 | ViewData["Title"] = "Two-factor authentication"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |

Your login is protected with an authenticator app. Enter your authenticator code below.

10 |
11 |
12 |
13 | 14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 |
22 | 26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 |

35 | Don't have access to your authenticator device? You can 36 | log in with a recovery code. 37 |

38 | 39 | @section Scripts { 40 | 41 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/LoginWithRecoveryCode.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LoginWithRecoveryCodeModel 3 | @{ 4 | ViewData["Title"] = "Recovery code verification"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |
9 |

10 | You have requested to log in with a recovery code. This login will not be remembered until you provide 11 | an authenticator app code at log in or disable 2FA and log in again. 12 |

13 |
14 |
15 |
16 |
17 |
18 | 19 | 20 | 21 |
22 | 23 |
24 |
25 |
26 | 27 | @section Scripts { 28 | 29 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model LogoutModel 3 | @{ 4 | ViewData["Title"] = "Log out"; 5 | } 6 | 7 | 8 |

@ViewData["Title"]

9 |

You have successfully logged out of the application.

10 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Globomantics.IdentityServer.Identity; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account 10 | { 11 | [AllowAnonymous] 12 | public class LogoutModel : PageModel 13 | { 14 | private readonly SignInManager _signInManager; 15 | private readonly ILogger _logger; 16 | 17 | public LogoutModel(SignInManager signInManager, ILogger logger) 18 | { 19 | _signInManager = signInManager; 20 | _logger = logger; 21 | } 22 | 23 | public void OnGet() 24 | { 25 | } 26 | 27 | public async Task OnPost(string returnUrl = null) 28 | { 29 | await _signInManager.SignOutAsync(); 30 | _logger.LogInformation("User logged out."); 31 | if (returnUrl != null) 32 | { 33 | return LocalRedirect(returnUrl); 34 | } 35 | else 36 | { 37 | return RedirectToPage(); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model ChangePasswordModel 4 | @{ 5 | ViewData["Title"] = "Change password"; 6 | ViewData["ActivePage"] = ManageNavPages.ChangePassword; 7 | } 8 | 9 |

@ViewData["Title"]

10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 | 31 |
32 |
33 |
34 | 35 | @section Scripts { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model Disable2faModel 4 | @{ 5 | ViewData["Title"] = "Disable two-factor authentication (2FA)"; 6 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 7 | } 8 | 9 | 10 |

@ViewData["Title"]

11 | 12 | 22 | 23 |
24 |
25 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/Disable2fa.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Globomantics.IdentityServer.Identity; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.RazorPages; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 10 | { 11 | public class Disable2faModel : PageModel 12 | { 13 | private readonly UserManager _userManager; 14 | private readonly ILogger _logger; 15 | 16 | public Disable2faModel( 17 | UserManager userManager, 18 | ILogger logger) 19 | { 20 | _userManager = userManager; 21 | _logger = logger; 22 | } 23 | 24 | [TempData] 25 | public string StatusMessage { get; set; } 26 | 27 | public async Task OnGet() 28 | { 29 | var user = await _userManager.GetUserAsync(User); 30 | if (user == null) 31 | { 32 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); 33 | } 34 | 35 | if (!await _userManager.GetTwoFactorEnabledAsync(user)) 36 | { 37 | throw new InvalidOperationException($"Cannot disable 2FA for user with ID '{_userManager.GetUserId(User)}' " + 38 | $"as it's not currently enabled."); 39 | } 40 | 41 | return Page(); 42 | } 43 | 44 | public async Task OnPostAsync() 45 | { 46 | var user = await _userManager.GetUserAsync(User); 47 | if (user == null) 48 | { 49 | return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); 50 | } 51 | 52 | var disable2faResult = await _userManager.SetTwoFactorEnabledAsync(user, false); 53 | if (!disable2faResult.Succeeded) 54 | { 55 | throw new InvalidOperationException($"Unexpected error occurred disabling 2FA for user with ID '{_userManager.GetUserId(User)}'."); 56 | } 57 | 58 | _logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", _userManager.GetUserId(User)); 59 | StatusMessage = "2fa has been disabled. You can reenable 2fa when you setup an authenticator app"; 60 | return RedirectToPage("./TwoFactorAuthentication"); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/GenerateRecoveryCodes.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model GenerateRecoveryCodesModel 4 | @{ 5 | ViewData["Title"] = "Generate two-factor authentication (2FA) recovery codes"; 6 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 7 | } 8 | 9 | 10 |

@ViewData["Title"]

11 | 24 |
25 |
26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model IndexModel 4 | @{ 5 | ViewData["Title"] = "Profile"; 6 | ViewData["ActivePage"] = ManageNavPages.Index; 7 | } 8 | 9 |

@ViewData["Title"]

10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 | 18 |
19 | @*
20 | 21 | 22 | 23 |
*@ 24 | 25 |
26 |
27 |
28 | 29 | @section Scripts { 30 | 31 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/ManageNavPages.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc.Rendering; 3 | 4 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 5 | { 6 | public static class ManageNavPages 7 | { 8 | public static string Index => "Index"; 9 | 10 | public static string Email => "Email"; 11 | 12 | public static string ChangePassword => "ChangePassword"; 13 | 14 | public static string DownloadPersonalData => "DownloadPersonalData"; 15 | 16 | public static string DeletePersonalData => "DeletePersonalData"; 17 | 18 | public static string ExternalLogins => "ExternalLogins"; 19 | 20 | public static string PersonalData => "PersonalData"; 21 | 22 | public static string TwoFactorAuthentication => "TwoFactorAuthentication"; 23 | 24 | public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index); 25 | 26 | public static string EmailNavClass(ViewContext viewContext) => PageNavClass(viewContext, Email); 27 | 28 | public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword); 29 | 30 | public static string DownloadPersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DownloadPersonalData); 31 | 32 | public static string DeletePersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, DeletePersonalData); 33 | 34 | public static string ExternalLoginsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ExternalLogins); 35 | 36 | public static string PersonalDataNavClass(ViewContext viewContext) => PageNavClass(viewContext, PersonalData); 37 | 38 | public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication); 39 | 40 | private static string PageNavClass(ViewContext viewContext, string page) 41 | { 42 | var activePage = viewContext.ViewData["ActivePage"] as string 43 | ?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName); 44 | return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model ResetAuthenticatorModel 4 | @{ 5 | ViewData["Title"] = "Reset authenticator key"; 6 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 7 | } 8 | 9 | 10 |

@ViewData["Title"]

11 | 21 |
22 |
23 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/ResetAuthenticator.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Globomantics.IdentityServer.Identity; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 9 | { 10 | public class ResetAuthenticatorModel : PageModel 11 | { 12 | UserManager _userManager; 13 | private readonly SignInManager _signInManager; 14 | ILogger _logger; 15 | 16 | public ResetAuthenticatorModel( 17 | UserManager userManager, 18 | SignInManager signInManager, 19 | ILogger logger) 20 | { 21 | _userManager = userManager; 22 | _signInManager = signInManager; 23 | _logger = logger; 24 | } 25 | 26 | [TempData] 27 | public string StatusMessage { get; set; } 28 | 29 | public async Task OnGet() 30 | { 31 | var user = await _userManager.GetUserAsync(User); 32 | if (user == null) 33 | { 34 | return NotFound($"Unable to load user with ID '{user.Id}'."); 35 | } 36 | 37 | return Page(); 38 | } 39 | 40 | public async Task OnPostAsync() 41 | { 42 | var user = await _userManager.GetUserAsync(User); 43 | if (user == null) 44 | { 45 | return NotFound($"Unable to load user with ID 'user.Id'."); 46 | } 47 | 48 | await _userManager.SetTwoFactorEnabledAsync(user, false); 49 | await _userManager.ResetAuthenticatorKeyAsync(user); 50 | _logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", user.Id); 51 | 52 | await _signInManager.RefreshSignInAsync(user); 53 | StatusMessage = "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key."; 54 | 55 | return RedirectToPage("./EnableAuthenticator"); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/SetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model SetPasswordModel 4 | @{ 5 | ViewData["Title"] = "Set password"; 6 | ViewData["ActivePage"] = ManageNavPages.ChangePassword; 7 | } 8 | 9 |

Set your password

10 | 11 |

12 | You do not have a local username/password for this site. Add a local 13 | account so you can log in without an external login. 14 |

15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 |
29 | 30 |
31 |
32 |
33 | 34 | @section Scripts { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ShowRecoveryCodesModel 3 | @{ 4 | ViewData["Title"] = "Recovery codes"; 5 | ViewData["ActivePage"] = "TwoFactorAuthentication"; 6 | } 7 | 8 | 9 |

@ViewData["Title"]

10 | 19 |
20 |
21 | @for (var row = 0; row < Model.RecoveryCodes.Length; row += 2) 22 | { 23 | @Model.RecoveryCodes[row] @Model.RecoveryCodes[row + 1]
24 | } 25 |
26 |
27 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/ShowRecoveryCodes.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 5 | { 6 | public class ShowRecoveryCodesModel : PageModel 7 | { 8 | [TempData] 9 | public string[] RecoveryCodes { get; set; } 10 | 11 | [TempData] 12 | public string StatusMessage { get; set; } 13 | 14 | public IActionResult OnGet() 15 | { 16 | if (RecoveryCodes == null || RecoveryCodes.Length == 0) 17 | { 18 | return RedirectToPage("./TwoFactorAuthentication"); 19 | } 20 | 21 | return Page(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/TwoFactorAuthentication.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @model TwoFactorAuthenticationModel 4 | @{ 5 | ViewData["Title"] = "Two-factor authentication (2FA)"; 6 | ViewData["ActivePage"] = ManageNavPages.TwoFactorAuthentication; 7 | } 8 | 9 | 10 |

@ViewData["Title"]

11 | @if (Model.Is2faEnabled) 12 | { 13 | if (Model.RecoveryCodesLeft == 0) 14 | { 15 |
16 | You have no recovery codes left. 17 |

You must generate a new set of recovery codes before you can log in with a recovery code.

18 |
19 | } 20 | else if (Model.RecoveryCodesLeft == 1) 21 | { 22 |
23 | You have 1 recovery code left. 24 |

You can generate a new set of recovery codes.

25 |
26 | } 27 | else if (Model.RecoveryCodesLeft <= 3) 28 | { 29 |
30 | You have @Model.RecoveryCodesLeft recovery codes left. 31 |

You should generate a new set of recovery codes.

32 |
33 | } 34 | 35 | if (Model.IsMachineRemembered) 36 | { 37 |
38 | 39 |
40 | } 41 | Disable 2FA 42 | Reset recovery codes 43 | } 44 | 45 |
Authenticator app
46 | @if (!Model.HasAuthenticator) 47 | { 48 | Add authenticator app 49 | } 50 | else 51 | { 52 | Setup authenticator app 53 | Reset authenticator app 54 | } 55 | 56 | @section Scripts { 57 | 58 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Areas/Identity/Pages/_Layout.cshtml"; 3 | } 4 | 5 |

Manage your account

6 | 7 |
8 |

Change your account settings

9 |
10 |
11 |
12 | 13 |
14 |
15 | @RenderBody() 16 |
17 |
18 |
19 | 20 | @section Scripts { 21 | @RenderSection("Scripts", required: false) 22 | } 23 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/_ManageNav.cshtml: -------------------------------------------------------------------------------- 1 | @using Globomantics.IdentityServer.Identity 2 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 3 | @inject SignInManager SignInManager 4 | @{ 5 | var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any(); 6 | } 7 | 18 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 | @if (!String.IsNullOrEmpty(Model)) 4 | { 5 | var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; 6 | 10 | } 11 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/Manage/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model RegisterConfirmationModel 3 | @{ 4 | ViewData["Title"] = "Register confirmation"; 5 | } 6 | 7 |

@ViewData["Title"]

8 | 9 |

10 | Please check your email to confirm your account. 11 |

12 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Globomantics.IdentityServer.Identity; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.AspNetCore.Identity.UI.Services; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account 10 | { 11 | [AllowAnonymous] 12 | public class RegisterConfirmationModel : PageModel 13 | { 14 | private readonly UserManager _userManager; 15 | //private readonly IEmailSender _sender; 16 | 17 | public RegisterConfirmationModel(UserManager userManager, IEmailSender sender) 18 | { 19 | _userManager = userManager; 20 | //_sender = sender; 21 | } 22 | 23 | public string Email { get; set; } 24 | 25 | public async Task OnGetAsync(string email, string returnUrl = null) 26 | { 27 | if (email == null) 28 | { 29 | return RedirectToPage("/Index"); 30 | } 31 | 32 | var user = await _userManager.FindByEmailAsync(email); 33 | if (user == null) 34 | { 35 | return NotFound($"Unable to load user with email '{email}'."); 36 | } 37 | 38 | //Email = email; 39 | //// Once you add a real email sender, you should remove this code that lets you confirm the account 40 | //DisplayConfirmAccountLink = true; 41 | //if (DisplayConfirmAccountLink) 42 | //{ 43 | // var userId = await _userManager.GetUserIdAsync(user); 44 | // var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); 45 | // code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); 46 | // EmailConfirmationUrl = Url.Page( 47 | // "/Account/ConfirmEmail", 48 | // pageHandler: null, 49 | // values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl }, 50 | // protocol: Request.Scheme); 51 | //} 52 | 53 | return Page(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResetPasswordModel 3 | @{ 4 | ViewData["Title"] = "Reset password"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |

Reset your password.

9 |
10 |
11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 | 31 |
32 |
33 |
34 | 35 | @section Scripts { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ResetPasswordConfirmationModel 3 | @{ 4 | ViewData["Title"] = "Reset password confirmation"; 5 | } 6 | 7 |

@ViewData["Title"]

8 |

9 | Your password has been reset. Please click here to log in. 10 |

11 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/ResetPasswordConfirmation.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | 4 | namespace Globomantics.IdentityServer.Areas.Identity.Pages.Account 5 | { 6 | [AllowAnonymous] 7 | public class ResetPasswordConfirmationModel : PageModel 8 | { 9 | public void OnGet() 10 | { 11 | 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/_StatusMessage.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 | @if (!String.IsNullOrEmpty(Model)) 4 | { 5 | var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; 6 | 10 | } 11 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/Account/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using Globomantics.IdentityServer.Areas.Identity 3 | @using Globomantics.IdentityServer.Areas.Identity.Pages 4 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 5 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Areas/Identity/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 |  2 | @{ 3 | Layout = "/Pages/Shared/_Layout.cshtml"; 4 | } 5 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/AccountOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | 7 | namespace IdentityServerHost.Quickstart.UI 8 | { 9 | public class AccountOptions 10 | { 11 | public static bool AllowLocalLogin = true; 12 | public static bool AllowRememberLogin = true; 13 | public static TimeSpan RememberMeLoginDuration = TimeSpan.FromDays(30); 14 | 15 | public static bool ShowLogoutPrompt = true; 16 | public static bool AutomaticRedirectAfterSignOut = false; 17 | 18 | public static string InvalidCredentialsErrorMessage = "Invalid username or password"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/ExternalProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class ExternalProvider 8 | { 9 | public string DisplayName { get; set; } 10 | public string AuthenticationScheme { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/LoggedOutViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class LoggedOutViewModel 8 | { 9 | public string PostLogoutRedirectUri { get; set; } 10 | public string ClientName { get; set; } 11 | public string SignOutIframeUrl { get; set; } 12 | 13 | public bool AutomaticRedirectAfterSignOut { get; set; } 14 | 15 | public string LogoutId { get; set; } 16 | public bool TriggerExternalSignout => ExternalAuthenticationScheme != null; 17 | public string ExternalAuthenticationScheme { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/LoginInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.ComponentModel.DataAnnotations; 6 | 7 | namespace IdentityServerHost.Quickstart.UI 8 | { 9 | public class LoginInputModel 10 | { 11 | [Required] 12 | public string Username { get; set; } 13 | [Required] 14 | public string Password { get; set; } 15 | public bool RememberLogin { get; set; } 16 | public string ReturnUrl { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace IdentityServerHost.Quickstart.UI 10 | { 11 | public class LoginViewModel : LoginInputModel 12 | { 13 | public bool AllowRememberLogin { get; set; } = true; 14 | public bool EnableLocalLogin { get; set; } = true; 15 | 16 | public IEnumerable ExternalProviders { get; set; } = Enumerable.Empty(); 17 | public IEnumerable VisibleExternalProviders => ExternalProviders.Where(x => !String.IsNullOrWhiteSpace(x.DisplayName)); 18 | 19 | public bool IsExternalLoginOnly => EnableLocalLogin == false && ExternalProviders?.Count() == 1; 20 | public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null; 21 | } 22 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/LogoutInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class LogoutInputModel 8 | { 9 | public string LogoutId { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/LogoutViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class LogoutViewModel : LogoutInputModel 8 | { 9 | public bool ShowLogoutPrompt { get; set; } = true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Account/RedirectViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | 6 | namespace IdentityServerHost.Quickstart.UI 7 | { 8 | public class RedirectViewModel 9 | { 10 | public string RedirectUrl { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Consent/ConsentInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace IdentityServerHost.Quickstart.UI 8 | { 9 | public class ConsentInputModel 10 | { 11 | public string Button { get; set; } 12 | public IEnumerable ScopesConsented { get; set; } 13 | public bool RememberConsent { get; set; } 14 | public string ReturnUrl { get; set; } 15 | public string Description { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Consent/ConsentOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class ConsentOptions 8 | { 9 | public static bool EnableOfflineAccess = true; 10 | public static string OfflineAccessDisplayName = "Offline Access"; 11 | public static string OfflineAccessDescription = "Access to your applications and resources, even when you are offline"; 12 | 13 | public static readonly string MustChooseOneErrorMessage = "You must pick at least one permission"; 14 | public static readonly string InvalidSelectionErrorMessage = "Invalid selection"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Consent/ConsentViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace IdentityServerHost.Quickstart.UI 8 | { 9 | public class ConsentViewModel : ConsentInputModel 10 | { 11 | public string ClientName { get; set; } 12 | public string ClientUrl { get; set; } 13 | public string ClientLogoUrl { get; set; } 14 | public bool AllowRememberConsent { get; set; } 15 | 16 | public IEnumerable IdentityScopes { get; set; } 17 | public IEnumerable ApiScopes { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Consent/ProcessConsentResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Models; 6 | 7 | namespace IdentityServerHost.Quickstart.UI 8 | { 9 | public class ProcessConsentResult 10 | { 11 | public bool IsRedirect => RedirectUri != null; 12 | public string RedirectUri { get; set; } 13 | public Client Client { get; set; } 14 | 15 | public bool ShowView => ViewModel != null; 16 | public ConsentViewModel ViewModel { get; set; } 17 | 18 | public bool HasValidationError => ValidationError != null; 19 | public string ValidationError { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Consent/ScopeViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class ScopeViewModel 8 | { 9 | public string Value { get; set; } 10 | public string DisplayName { get; set; } 11 | public string Description { get; set; } 12 | public bool Emphasize { get; set; } 13 | public bool Required { get; set; } 14 | public bool Checked { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Device/DeviceAuthorizationInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class DeviceAuthorizationInputModel : ConsentInputModel 8 | { 9 | public string UserCode { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Device/DeviceAuthorizationViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public class DeviceAuthorizationViewModel : ConsentViewModel 8 | { 9 | public string UserCode { get; set; } 10 | public bool ConfirmUserCode { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Diagnostics/DiagnosticsController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Microsoft.AspNetCore.Authentication; 8 | using Microsoft.AspNetCore.Authorization; 9 | using Microsoft.AspNetCore.Mvc; 10 | 11 | namespace IdentityServerHost.Quickstart.UI 12 | { 13 | [SecurityHeaders] 14 | [Authorize] 15 | public class DiagnosticsController : Controller 16 | { 17 | public async Task Index() 18 | { 19 | //var localAddresses = new string[] { "127.0.0.1", "::1", HttpContext.Connection.LocalIpAddress.ToString() }; 20 | //if (!localAddresses.Contains(HttpContext.Connection.RemoteIpAddress.ToString())) 21 | //{ 22 | // return NotFound(); 23 | //} 24 | 25 | var model = new DiagnosticsViewModel(await HttpContext.AuthenticateAsync()); 26 | return View(model); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Diagnostics/DiagnosticsViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityModel; 6 | using Microsoft.AspNetCore.Authentication; 7 | using Newtonsoft.Json; 8 | using System.Collections.Generic; 9 | using System.Text; 10 | 11 | namespace IdentityServerHost.Quickstart.UI 12 | { 13 | public class DiagnosticsViewModel 14 | { 15 | public DiagnosticsViewModel(AuthenticateResult result) 16 | { 17 | AuthenticateResult = result; 18 | 19 | if (result.Properties.Items.ContainsKey("client_list")) 20 | { 21 | var encoded = result.Properties.Items["client_list"]; 22 | var bytes = Base64Url.Decode(encoded); 23 | var value = Encoding.UTF8.GetString(bytes); 24 | 25 | Clients = JsonConvert.DeserializeObject(value); 26 | } 27 | } 28 | 29 | public AuthenticateResult AuthenticateResult { get; } 30 | public IEnumerable Clients { get; } = new List(); 31 | } 32 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IdentityServer4.Models; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace IdentityServerHost.Quickstart.UI 6 | { 7 | public static class Extensions 8 | { 9 | /// 10 | /// Checks if the redirect URI is for a native client. 11 | /// 12 | /// 13 | public static bool IsNativeClient(this AuthorizationRequest context) 14 | { 15 | return !context.RedirectUri.StartsWith("https", StringComparison.Ordinal) 16 | && !context.RedirectUri.StartsWith("http", StringComparison.Ordinal); 17 | } 18 | 19 | public static IActionResult LoadingPage(this Controller controller, string viewName, string redirectUri) 20 | { 21 | controller.HttpContext.Response.StatusCode = 200; 22 | controller.HttpContext.Response.Headers["Location"] = ""; 23 | 24 | return controller.View(viewName, new RedirectViewModel { RedirectUrl = redirectUri }); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Grants/GrantsViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace IdentityServerHost.Quickstart.UI 9 | { 10 | public class GrantsViewModel 11 | { 12 | public IEnumerable Grants { get; set; } 13 | } 14 | 15 | public class GrantViewModel 16 | { 17 | public string ClientId { get; set; } 18 | public string ClientName { get; set; } 19 | public string ClientUrl { get; set; } 20 | public string ClientLogoUrl { get; set; } 21 | public string Description { get; set; } 22 | public DateTime Created { get; set; } 23 | public DateTime? Expires { get; set; } 24 | public IEnumerable IdentityGrantNames { get; set; } 25 | public IEnumerable ApiGrantNames { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Home/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Models; 6 | 7 | namespace IdentityServerHost.Quickstart.UI 8 | { 9 | public class ErrorViewModel 10 | { 11 | public ErrorViewModel() 12 | { 13 | } 14 | 15 | public ErrorViewModel(string error) 16 | { 17 | Error = new ErrorMessage { Error = error }; 18 | } 19 | 20 | public ErrorMessage Error { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Controllers/Home/HomeController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Services; 6 | using Microsoft.AspNetCore.Authorization; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.Extensions.Hosting; 10 | using Microsoft.Extensions.Logging; 11 | using System.Threading.Tasks; 12 | 13 | namespace IdentityServerHost.Quickstart.UI 14 | { 15 | [SecurityHeaders] 16 | [AllowAnonymous] 17 | public class HomeController : Controller 18 | { 19 | private readonly IIdentityServerInteractionService _interaction; 20 | private readonly IWebHostEnvironment _environment; 21 | private readonly ILogger _logger; 22 | 23 | public HomeController(IIdentityServerInteractionService interaction, IWebHostEnvironment environment, ILogger logger) 24 | { 25 | _interaction = interaction; 26 | _environment = environment; 27 | _logger = logger; 28 | } 29 | 30 | public IActionResult Index() 31 | { 32 | //if (_environment.IsDevelopment()) 33 | //{ 34 | // only show in development 35 | return View(); 36 | //} 37 | 38 | //_logger.LogInformation("Homepage is disabled in production. Returning 404."); 39 | //return NotFound(); 40 | } 41 | 42 | /// 43 | /// Shows the error page 44 | /// 45 | public async Task Error(string errorId) 46 | { 47 | var vm = new ErrorViewModel(); 48 | 49 | // retrieve error details from identityserver 50 | var message = await _interaction.GetErrorContextAsync(errorId); 51 | if (message != null) 52 | { 53 | vm.Error = message; 54 | 55 | if (!_environment.IsDevelopment()) 56 | { 57 | // only show in development 58 | message.ErrorDescription = null; 59 | } 60 | } 61 | 62 | return View("Error", vm); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Data/Company.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Globomantics.IdentityServer.Data 4 | { 5 | public class Company 6 | { 7 | public int Id { get; set; } 8 | public string Name { get; set; } 9 | public List Members { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Data/CompanyMember.cs: -------------------------------------------------------------------------------- 1 | namespace Globomantics.IdentityServer.Data 2 | { 3 | public class CompanyMember 4 | { 5 | public int Id { get; set; } 6 | public int CompanyId { get; set; } 7 | public string MemberEmail { get; set; } 8 | public Company Company { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base 4 | WORKDIR /app 5 | 6 | FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build 7 | WORKDIR /src 8 | COPY ["Globomantics.IdentityServer/Globomantics.IdentityServer.csproj", "Globomantics.IdentityServer/"] 9 | RUN dotnet restore "Globomantics.IdentityServer/Globomantics.IdentityServer.csproj" 10 | COPY . . 11 | WORKDIR "/src/Globomantics.IdentityServer" 12 | RUN dotnet build "Globomantics.IdentityServer.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "Globomantics.IdentityServer.csproj" -c Release -o /app/publish 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | ENV ASPNETCORE_URLS=http://*:5000 21 | ENTRYPOINT ["dotnet", "Globomantics.IdentityServer.dll"] 22 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Globomantics.IdentityServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0 5 | 3c71267f-6158-4bf4-8888-25db434e0cfc 6 | Linux 7 | ..\docker-compose.dcproj 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | all 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomIdentityOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IdentityModel; 3 | using Microsoft.AspNetCore.Identity; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace Globomantics.IdentityServer.Identity 7 | { 8 | public class CustomIdentityOptions : IConfigureOptions 9 | { 10 | public void Configure(IdentityOptions options) 11 | { 12 | options.Password.RequiredLength = 6; 13 | options.Password.RequireDigit = true; 14 | options.Password.RequireLowercase = true; 15 | options.Password.RequireUppercase = true; 16 | options.Password.RequireNonAlphanumeric = true; 17 | options.Password.RequiredUniqueChars = 1; 18 | 19 | options.SignIn.RequireConfirmedEmail = true; 20 | options.SignIn.RequireConfirmedAccount = true; 21 | 22 | options.Lockout.MaxFailedAccessAttempts = 3; // 5 23 | options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); 24 | options.Lockout.AllowedForNewUsers = true; 25 | 26 | options.ClaimsIdentity.RoleClaimType = JwtClaimTypes.Role; 27 | options.ClaimsIdentity.UserIdClaimType = JwtClaimTypes.Subject; 28 | options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.Name; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomPasswordHasher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using Microsoft.AspNetCore.Identity; 4 | 5 | namespace Globomantics.IdentityServer.Identity 6 | { 7 | public class CustomPasswordHasher : PasswordHasher 8 | { 9 | public override PasswordVerificationResult VerifyHashedPassword(CustomUser user, string hashedPassword, 10 | string providedPassword) 11 | { 12 | if (!string.IsNullOrEmpty(user.PasswordSalt)) 13 | { 14 | if (VerifyLegacyPassword(Convert.FromBase64String(user.PasswordSalt), 15 | hashedPassword, providedPassword)) 16 | { 17 | return PasswordVerificationResult.SuccessRehashNeeded; 18 | } 19 | 20 | return PasswordVerificationResult.Failed; 21 | } 22 | 23 | return base.VerifyHashedPassword(user, hashedPassword, providedPassword); 24 | } 25 | 26 | private bool VerifyLegacyPassword(byte[] salt, string hashedPassword, string providedPassword) 27 | { 28 | var hasher = new Rfc2898DeriveBytes(providedPassword, salt) { IterationCount = 100 }; 29 | var hashedVersionOfProvidedPassword = Convert.ToBase64String(hasher.GetBytes(128)); 30 | return hashedPassword == hashedVersionOfProvidedPassword; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomPasswordValidator.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNetCore.Identity; 3 | 4 | namespace Globomantics.IdentityServer.Identity 5 | { 6 | public class CustomPasswordValidator : IPasswordValidator 7 | { 8 | public Task ValidateAsync(UserManager manager, CustomUser user, string password) 9 | { 10 | if (password.ToLowerInvariant().Contains("glob")) 11 | { 12 | return Task.FromResult(IdentityResult.Failed(new IdentityError 13 | { 14 | Code = "GlobomanticsVariant", 15 | Description = "Variants of Globomantics cannot be used in a password." 16 | })); 17 | } 18 | 19 | return Task.FromResult(IdentityResult.Success); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomUser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Identity; 3 | 4 | namespace Globomantics.IdentityServer.Identity 5 | { 6 | public class CustomUser : IdentityUser 7 | { 8 | public int UserId { get; set; } 9 | public string LoginName { get; set; } 10 | public string PasswordSalt { get; set; } 11 | public DateTime PasswordModifiedDate { get; set; } 12 | public DateTime? LastLoginDate { get; set; } 13 | public DateTime CreateDate { get; set; } 14 | public short Status { get; set; } 15 | 16 | public override int Id => UserId; 17 | public override string NormalizedEmail => LoginName.ToUpperInvariant(); 18 | public override string Email => LoginName; 19 | public override string UserName => LoginName; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomUserManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Identity; 5 | using Microsoft.Extensions.Logging; 6 | using Microsoft.Extensions.Options; 7 | 8 | namespace Globomantics.IdentityServer.Identity 9 | { 10 | public class CustomUserManager : UserManager 11 | { 12 | //https://github.com/dotnet/aspnetcore/blob/a190fd34854542266956b1af980c19afacb95feb/src/Identity/Extensions.Core/src/UserManager.cs 13 | public CustomUserManager(IUserStore store, 14 | IOptions optionsAccessor, 15 | IPasswordHasher passwordHasher, 16 | IEnumerable> userValidators, 17 | IEnumerable> passwordValidators, 18 | ILookupNormalizer keyNormalizer, 19 | IdentityErrorDescriber errors, 20 | IServiceProvider services, 21 | ILogger> logger) 22 | : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, 23 | keyNormalizer, errors, services, logger) 24 | { 25 | } 26 | 27 | public override async Task AccessFailedAsync(CustomUser user) 28 | { 29 | ThrowIfDisposed(); 30 | var store = GetUserLockoutStore(); 31 | if (user == null) 32 | { 33 | throw new ArgumentNullException(nameof(user)); 34 | } 35 | 36 | // If this puts the user over the threshold for lockout, 37 | // lock them out and reset the access failed count 38 | var count = await store.IncrementAccessFailedCountAsync(user, CancellationToken); 39 | if (count < Options.Lockout.MaxFailedAccessAttempts || !user.LockoutEnabled) 40 | { 41 | return await UpdateUserAsync(user); 42 | } 43 | Logger.LogWarning(12, "User is locked out."); 44 | await store.SetLockoutEndDateAsync(user, 45 | DateTimeOffset.UtcNow.Add(Options.Lockout.DefaultLockoutTimeSpan), 46 | CancellationToken); 47 | await store.ResetAccessFailedCountAsync(user, CancellationToken); 48 | return await UpdateUserAsync(user); 49 | } 50 | 51 | private IUserLockoutStore GetUserLockoutStore() 52 | { 53 | if (!(Store is IUserLockoutStore cast)) 54 | { 55 | throw new NotSupportedException("User store does not implement IUserLockoutStore."); 56 | } 57 | return cast; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomUserStore-ClaimsAndRoles.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Claims; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Dapper; 7 | using Globomantics.IdentityServer.Data; 8 | using IdentityModel; 9 | using Microsoft.AspNetCore.Identity; 10 | 11 | namespace Globomantics.IdentityServer.Identity 12 | { 13 | public partial class CustomUserStore : IUserClaimStore 14 | { 15 | public async Task> GetClaimsAsync(CustomUser user, CancellationToken cancellationToken) 16 | { 17 | var claims = new List(); 18 | var memberInfo = await _db.QueryFirstOrDefaultAsync( 19 | "SELECT * FROM CompanyMembers WHERE MemberEmail = @LoginName", 20 | new { user.LoginName }); 21 | 22 | if (memberInfo != null) 23 | { 24 | claims.Add(new Claim("CompanyId", Convert.ToString(memberInfo.CompanyId))); 25 | } 26 | 27 | claims.Add(user.LoginName == "kim@mars.com" 28 | ? new Claim(JwtClaimTypes.Role, "admin") 29 | : new Claim(JwtClaimTypes.Role, "general")); 30 | 31 | claims.Add(new Claim("MfaEnabled", Convert.ToString(user.TwoFactorEnabled))); 32 | 33 | return claims; 34 | } 35 | 36 | public Task AddClaimsAsync(CustomUser user, IEnumerable claims, CancellationToken cancellationToken) 37 | { 38 | throw new NotImplementedException(); 39 | } 40 | 41 | public Task ReplaceClaimAsync(CustomUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken) 42 | { 43 | throw new NotImplementedException(); 44 | } 45 | 46 | public Task RemoveClaimsAsync(CustomUser user, IEnumerable claims, CancellationToken cancellationToken) 47 | { 48 | throw new NotImplementedException(); 49 | } 50 | 51 | public Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken) 52 | { 53 | throw new NotImplementedException(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Identity/CustomUserValidator.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Threading.Tasks; 3 | using Dapper; 4 | using Globomantics.IdentityServer.Data; 5 | using Microsoft.AspNetCore.Identity; 6 | 7 | namespace Globomantics.IdentityServer.Identity 8 | { 9 | public class CustomUserValidator : IUserValidator 10 | { 11 | private readonly IDbConnection _db; 12 | 13 | public CustomUserValidator(IDbConnection db) 14 | { 15 | _db = db; 16 | } 17 | 18 | public Task ValidateAsync(UserManager manager, CustomUser user) 19 | { 20 | var knownCompanyMember = _db.QuerySingleOrDefault( 21 | @"SELECT * FROM dbo.CompanyMembers WHERE MemberEmail = @Email", 22 | new {Email = user.Email}); 23 | if (knownCompanyMember != null) 24 | { 25 | return Task.FromResult(IdentityResult.Success); 26 | } 27 | 28 | return Task.FromResult(IdentityResult.Failed(new IdentityError 29 | { 30 | Code = "UnknownMember", 31 | Description = "Provided username is not a valid company member." 32 | })); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Initialization/MigrationHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using IdentityServer4.EntityFramework.DbContexts; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Serilog; 8 | 9 | namespace Globomantics.IdentityServer.Initialization 10 | { 11 | public static class MigrationHelper 12 | { 13 | public static void ApplyDatabaseSchema(this IApplicationBuilder app) 14 | { 15 | using var serviceScope = app.ApplicationServices.GetService()?.CreateScope(); 16 | try 17 | { 18 | serviceScope?.ServiceProvider.GetRequiredService().Database.Migrate(); 19 | serviceScope?.ServiceProvider.GetRequiredService().Database.Migrate(); 20 | } 21 | catch (Exception) 22 | { 23 | // If the database is not available yet just wait and try again 24 | var dbConnection = serviceScope?.ServiceProvider.GetRequiredService().Database 25 | .GetConnectionString(); 26 | Log.Information($"Failed performing migrations: {dbConnection}"); 27 | 28 | Thread.Sleep(TimeSpan.FromSeconds(15)); 29 | app.ApplyDatabaseSchema(); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model ErrorModel 3 | @{ 4 | ViewData["Title"] = "Error"; 5 | } 6 | 7 |

Error.

8 |

An error occurred while processing your request.

9 | 10 | @if (Model.ShowRequestId) 11 | { 12 |

13 | Request ID: @Model.RequestId 14 |

15 | } 16 | 17 |

Development Mode

18 |

19 | Swapping to the Development environment displays detailed information about the error that occurred. 20 |

21 |

22 | The Development environment shouldn't be enabled for deployed applications. 23 | It can result in displaying sensitive information from exceptions to end users. 24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 25 | and restarting the app. 26 |

27 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Globomantics.Core.Pages 7 | { 8 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 9 | public class ErrorModel : PageModel 10 | { 11 | public string RequestId { get; set; } 12 | 13 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 14 | 15 | private readonly ILogger _logger; 16 | 17 | public ErrorModel(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | public void OnGet() 23 | { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Globomantics.IdentityServer.Identity 2 | @using Microsoft.AspNetCore.Identity 3 | 4 | @inject SignInManager SignInManager 5 | @inject UserManager UserManager 6 | 7 | 36 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/TwoFactorChallenge.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Globomantics.Core.Pages.TwoFactorChallengeModel 3 | @{ 4 | } 5 | 6 |

@ViewData["Title"]

7 |
8 |

To access the requested feature you will need to verify via authentication:

9 |
10 |
11 |
12 |
13 | 14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 |
22 | 23 |
24 | 25 | @section Scripts { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @namespace Globomantics.Core.Pages 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Hosting; 4 | using Serilog; 5 | 6 | namespace Globomantics.IdentityServer 7 | { 8 | public class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | try 13 | { 14 | CreateHostBuilder(args).Build().Run(); 15 | } 16 | catch (Exception ex) 17 | { 18 | Console.WriteLine(ex.Message); 19 | } 20 | finally 21 | { 22 | Log.CloseAndFlush(); 23 | } 24 | } 25 | 26 | public static IHostBuilder CreateHostBuilder(string[] args) => 27 | Host.CreateDefaultBuilder(args) 28 | .UseSerilog((ctx, provider, loggerConfig) => 29 | { 30 | loggerConfig 31 | .ReadFrom.Configuration(ctx.Configuration) // minimum levels defined per project in json files 32 | .Enrich.FromLogContext() 33 | .WriteTo.Console() 34 | .WriteTo.Seq("http://globoseq"); 35 | }) 36 | .ConfigureWebHostDefaults(webBuilder => 37 | { 38 | webBuilder.UseStartup(); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "https://localhost:44377/", 7 | "sslPort": 44377 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "https://localhost:44377/.well-known/openid-configuration", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Globomantics.IdentityServer": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | }, 25 | "dotnetRunMessages": "true", 26 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 27 | }, 28 | "Docker (1)": { 29 | "commandName": "Docker", 30 | "launchBrowser": true, 31 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", 32 | "publishAllPorts": true, 33 | "useSSL": true 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Services/EmailSender.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Mail; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Identity.UI.Services; 4 | using Microsoft.Extensions.Configuration; 5 | 6 | namespace Globomantics.IdentityServer.Services 7 | { 8 | public class EmailSender : IEmailSender 9 | { 10 | private readonly string _smtpServer; 11 | private readonly int _smtpPort; 12 | private readonly string _fromAddress; 13 | 14 | public EmailSender(IConfiguration config) 15 | { 16 | _smtpServer = config.GetValue("Email:SmtpServer"); 17 | _smtpPort = config.GetValue("Email:SmtpPort"); 18 | _fromAddress = config.GetValue("Email:SenderAddress"); 19 | } 20 | public async Task SendEmailAsync(string email, string subject, string htmlMessage) 21 | { 22 | var message = new MailMessage 23 | { 24 | From = new MailAddress(_fromAddress), 25 | Subject = subject, 26 | Body = htmlMessage, 27 | IsBodyHtml = true 28 | }; 29 | message.To.Add(new MailAddress(email)); 30 | 31 | using var client = new SmtpClient(_smtpServer, _smtpPort); 32 | await client.SendMailAsync(message); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Account/AccessDenied.cshtml: -------------------------------------------------------------------------------- 1 |  2 |
3 |
4 |

Access Denied

5 |

You do not have access to that resource.

6 |
7 |
-------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Account/LoggedOut.cshtml: -------------------------------------------------------------------------------- 1 | @model LoggedOutViewModel 2 | 3 | @{ 4 | // set this so the layout rendering sees an anonymous user 5 | ViewData["signed-out"] = true; 6 | } 7 | 8 |
9 |

10 | Logout 11 | You are now logged out 12 |

13 | 14 | @if (Model.PostLogoutRedirectUri != null) 15 | { 16 |
17 | Click here to return to the 18 | @Model.ClientName application. 19 |
20 | } 21 | 22 | @if (Model.SignOutIframeUrl != null) 23 | { 24 | 25 | } 26 |
27 | 28 | @section scripts 29 | { 30 | @if (Model.AutomaticRedirectAfterSignOut) 31 | { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @model LogoutViewModel 2 | 3 |
4 |
5 |

Logout

6 |

Would you like to logut of IdentityServer?

7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Device/Success.cshtml: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

Success

5 |

You have successfully authorized the device

6 |
7 |
8 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Device/UserCodeCapture.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 |
4 |
5 |

User Code

6 |

Please enter the code displayed on your device.

7 |
8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 | 16 | 17 |
18 | 19 | 20 |
21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Diagnostics/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model DiagnosticsViewModel 2 | 3 |
4 |
5 |

Authentication Cookie

6 |
7 | 8 |
9 |
10 |
11 |
12 |

Claims

13 |
14 |
15 |
16 | @foreach (var claim in Model.AuthenticateResult.Principal.Claims) 17 | { 18 |
@claim.Type
19 |
@claim.Value
20 | } 21 |
22 |
23 |
24 |
25 | 26 |
27 |
28 |
29 |

Properties

30 |
31 |
32 |
33 | @foreach (var prop in Model.AuthenticateResult.Properties.Items) 34 | { 35 |
@prop.Key
36 |
@prop.Value
37 | } 38 | @if (Model.Clients.Any()) 39 | { 40 |
Clients
41 |
42 | @{ 43 | var clients = Model.Clients.ToArray(); 44 | for(var i = 0; i < clients.Length; i++) 45 | { 46 | @clients[i] 47 | if (i < clients.Length - 1) 48 | { 49 | , 50 | } 51 | } 52 | } 53 |
54 | } 55 |
56 |
57 |
58 |
59 |
60 |
61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Diagnostics 2 | 3 | @{ 4 | var version = FileVersionInfo.GetVersionInfo(typeof(IdentityServer4.Hosting.IdentityServerMiddleware).Assembly.Location).ProductVersion.Split('+').First(); 5 | } 6 | 7 |
8 |

9 | 10 | Welcome to IdentityServer4 11 | (version @version) 12 |

13 | 14 |
    15 |
  • 16 | IdentityServer publishes a 17 | discovery document 18 | where you can find metadata and links to all the endpoints, key material, etc. 19 |
  • 20 |
  • 21 | Click here to see the claims for your current session. 22 |
  • 23 |
  • 24 | Click here to manage your stored grants. 25 |
  • 26 |
  • 27 | Here are links to the 28 | source code repository, 29 | and ready to use samples. 30 |
  • 31 |
32 |
33 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | 3 | @{ 4 | var error = Model?.Error?.Error; 5 | var errorDescription = Model?.Error?.ErrorDescription; 6 | var request_id = Model?.Error?.RequestId; 7 | } 8 | 9 |
10 |
11 |

Error

12 |
13 | 14 |
15 |
16 |
17 | Sorry, there was an error 18 | 19 | @if (error != null) 20 | { 21 | 22 | 23 | : @error 24 | 25 | 26 | 27 | if (errorDescription != null) 28 | { 29 |
@errorDescription
30 | } 31 | } 32 |
33 | 34 | @if (request_id != null) 35 | { 36 |
Request Id: @request_id
37 | } 38 |
39 |
40 |
41 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/Redirect.cshtml: -------------------------------------------------------------------------------- 1 | @model RedirectViewModel 2 | 3 |
4 |
5 |

You are now being returned to the application

6 |

Once complete, you may close this tab.

7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | IdentityServer4 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | @RenderBody() 21 |
22 | 23 | 24 | 25 | 26 | @RenderSection("scripts", required: false) 27 | 28 | 29 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using Globomantics.IdentityServer.Identity 3 | 4 | @inject SignInManager SignInManager 5 | @inject UserManager UserManager 6 | 7 | 29 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/_Nav.cshtml: -------------------------------------------------------------------------------- 1 | @using IdentityServer4.Extensions 2 | @using Microsoft.AspNetCore.Identity 3 | @using Globomantics.IdentityServer.Identity 4 | @using Globomantics.IdentityServer.Areas.Identity.Pages.Account.Manage 5 | @inject SignInManager SignInManager 6 | 7 | @{ 8 | string name = null; 9 | if (!true.Equals(ViewData["signed-out"])) 10 | { 11 | name = Context.User?.GetDisplayName(); 12 | } 13 | } 14 | 15 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/_ScopeListItem.cshtml: -------------------------------------------------------------------------------- 1 | @model ScopeViewModel 2 | 3 |
  • 4 | 24 | @if (Model.Required) 25 | { 26 | (required) 27 | } 28 | @if (Model.Description != null) 29 | { 30 | 33 | } 34 |
  • -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/Shared/_ValidationSummary.cshtml: -------------------------------------------------------------------------------- 1 | @if (ViewContext.ModelState.IsValid == false) 2 | { 3 |
    4 | Error 5 |
    6 |
    7 | } -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using IdentityServerHost.Quickstart.UI 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "IS4DbConnection": "Server=globosql;Database=GlobomanticsIdSrv;User Id=sa;Password=Sqlc0ntainersFTW!;MultipleActiveResultSets=true", 4 | "GlobomanticsDb": "Server=globosql;Database=Globomantics;User Id=globo_dbuser;Password=SqlonLinux?!;MultipleActiveResultSets=true" 5 | }, 6 | "Email": { 7 | "SmtpServer": "globosmtp", 8 | "SmtpPort": 25, 9 | "SenderAddress": "donotreply@globomantics.com" 10 | }, 11 | "Serilog": { 12 | "MinimumLevel": { 13 | "Default": "Debug", 14 | "Override": { 15 | "Microsoft": "Warning", 16 | "System": "Warning" 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/tempkey.jwk: -------------------------------------------------------------------------------- 1 | {"alg":"RS256","d":"AMl2pGMv3w3t-YWT7sRSysPvropvfgXW8ChqrE1x0_mn9-rICPf7_q9a6wqvIES0sO3e6OLhOphDvqa1KNtf9bjpC6uy8qZqCeCWkYCe1Dxr4fwsfZp0FIh-Ow8rnDkmjgTetHbDgknbzkL2d1Dqm7wJer5LZPt-EcdHjOtywJAMJdQaEfLF-5NJ6Ssa9K1CzgvMbO-G91yb-pkHMUaOgOH8-Im8Onm2W30_uYH0OKCu6olnU44g6aXSAQEHGlEKpVNNSCDDa6udMfNOpi3AfSY-SWM3psyD-Utx-sOpF8fkelDqYvuktarj2rsCJE9nVUNmkxsRhUpxue6XnGhvdQ","dp":"PTkgn_rlVv7YzCMNEFO91qv0m9lePAOaZcI2kzjJ6kOwUMkHBkPCvNnBD5pgU0Jcl4bos4vWVw_AX7QuYN1lSQxRY6-ox2HmFrgajcslZsqMUicLBqZtnlfHYwVTMvpvWnISIIrS8h7CosH9XIIrSz6nUXuh0n3VK0zblLZUFOE","dq":"N44dfc6PB2u2yu1Zd4NfnGib59nzyhD9HPl0joYJKasYr4qzxaypifHimKx5B7vwtepSvjf5mznonel13OmE_h_x069B4T8_8ScWy0wl3_Smhboz1tnMIW9nC-hJ5hwlIdd2GEGm6Zx8VBsWANISIgmRyKvrKoLH5_k37S4Wzws","e":"AQAB","kid":"42EAED855D2704C9F29B9395CB4D326F","kty":"RSA","n":"vOvFuJKHQmRdQii_nrdhm2iB2pnRixhYJOd14_p-_LP9uW-LfLxzB9R-ByD6VDzqFwhJ2ksgU-uwNs__l3m7owsI_AJ0mxCWT1tgq8gMDk0BUaKsVUfoi1JMeVfWK9lYTjrRbTdM8VdMEZmIO2-E1Igr3gehjI2lS1h0dxcitMzvtv39cuXEvB231xlmlz1BAxhoUaQHY9IuqD863d3XjAcG-m8CkInC0ePdJAbWdZWi53H-35djoJEJsEZvuZuB4qQO1mWMdyIkS8HZ9lSokKQ_7kUYBCuoW5Nh-Yr9FPCYu8saRCOUQtRatZx_62Cdc4gXqjXt2Y_yQxhzlbgD2Q","p":"0BxwgYisvtWB8591UPQUG7-Qx-MHS3GITbYE9V6AW_VOPYWFaHSKhjh7xOD7S3Rrauhr2ZtuTI_tFbrty-TjZ7IrjUq8HC9XpJ-QwWdKzrYb_9UMSpaushprbgElE4OJTmmKjQZrdUtFENhGFoNlhA_3t2HFIH_-2LlYnJmBGtc","q":"6GTeOUoEkyu-8bzIih682uUw6dL-WZbKBzLsovxRf92HOX2grZqlXxsusVcJ6_ugzOOHrjabDeXBWWXYEij6t2I4K88i1DXxEl3jo9Md2uJJA34GIN7L8b5rNlpCaZ97rYZlZuOrR-9-25GCms6emTt9xgVCRBrFmLdmPxKtMM8","qi":"f7yX0D0me5EV-2qbc_Xzus1kkks-i7D0yL25t5Z_d7mc6FhVLdSiIy-IUa0ZA6urpc1-HU6k2ZaiAbuWqiSh8PMYRSFz_aGWUmcWtPlsZGrpIOxwOeHRPAboIcut2BIPNUGeUIVCBxrHp-CBzCS4o0VzkvGh5wlbLyEGOkpqm9U"} -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/css/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/css/.DS_Store -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/css/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/css/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | for details on configuring this project to bundle and minify static web assets. */ 3 | 4 | a.navbar-brand { 5 | white-space: normal; 6 | text-align: center; 7 | word-break: break-all; 8 | } 9 | 10 | /* Provide sufficient contrast against white background */ 11 | a { 12 | color: #0366d6; 13 | } 14 | 15 | .btn-primary { 16 | color: #fff; 17 | background-color: #1b6ec2; 18 | border-color: #1861ac; 19 | } 20 | 21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link { 22 | color: #fff; 23 | background-color: #1b6ec2; 24 | border-color: #1861ac; 25 | } 26 | 27 | /* Sticky footer styles 28 | -------------------------------------------------- */ 29 | html { 30 | font-size: 14px; 31 | } 32 | @media (min-width: 768px) { 33 | html { 34 | font-size: 16px; 35 | } 36 | } 37 | 38 | .border-top { 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | .border-bottom { 42 | border-bottom: 1px solid #e5e5e5; 43 | } 44 | 45 | .box-shadow { 46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 47 | } 48 | 49 | button.accept-policy { 50 | font-size: 1rem; 51 | line-height: inherit; 52 | } 53 | 54 | /* Sticky footer styles 55 | -------------------------------------------------- */ 56 | html { 57 | position: relative; 58 | min-height: 100%; 59 | } 60 | 61 | body { 62 | /* Margin bottom by footer height */ 63 | margin-bottom: 60px; 64 | } 65 | .footer { 66 | position: absolute; 67 | bottom: 0; 68 | width: 100%; 69 | white-space: nowrap; 70 | line-height: 60px; /* Vertically center the text there */ 71 | } 72 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/Bitmap(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/Bitmap(1).png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/Bitmap-footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/Bitmap-footer.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/Bitmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/Bitmap.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/G.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/G.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/Hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/Hero.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/avatar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1F396E79-704A-4B98-A5D9-46E8C401B934 5 | Created with sketchtool. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/banner.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/banner3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/banner3.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/girl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/girl.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/hero image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/hero image.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/mobileBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/mobileBanner.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/pluralsight-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/pluralsight-white.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/sec2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/sec2.jpg -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/sec3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/sec3.jpg -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_211091626.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_211091626.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_252243790.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_252243790.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_564197512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_564197512.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_645747736.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_645747736.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_662279290.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_662279290.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_725256820.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_725256820.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/images/shutterstock_734412034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/Globomantics.IdentityServer/wwwroot/images/shutterstock_734412034.png -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/js/counterup.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery.counterup.js 1.0 3 | * 4 | * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 5 | * Released under the GPL v2 License 6 | * 7 | * Date: Nov 26, 2013 8 | */(function(e){"use strict";e.fn.counterUp=function(t){var n=e.extend({time:400,delay:10},t);return this.each(function(){var t=e(this),r=n,i=function(){var e=[],n=r.time/r.delay,i=t.text(),s=/[0-9]+,[0-9]+/.test(i);i=i.replace(/,/g,"");var o=/^[0-9]+$/.test(i),u=/^[0-9]+\.[0-9]+$/.test(i),a=u?(i.split(".")[1]||[]).length:0;for(var f=n;f>=1;f--){var l=parseInt(i/n*f);u&&(l=parseFloat(i/n*f).toFixed(a));if(s)while(/(\d+)(\d{3})/.test(l.toString()))l=l.toString().replace(/(\d+)(\d{3})/,"$1,$2");e.unshift(l)}t.data("counterup-nums",e);t.text("0");var c=function(){t.text(t.data("counterup-nums").shift());if(t.data("counterup-nums").length)setTimeout(t.data("counterup-func"),r.delay);else{delete t.data("counterup-nums");t.data("counterup-nums",null);t.data("counterup-func",null)}};t.data("counterup-func",c);setTimeout(t.data("counterup-func"),r.delay)};t.waypoint(i,{offset:"100%",triggerOnce:!0})})}})(jQuery); -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification 2 | // for details on configuring this project to bundle and minify static web assets. 3 | 4 | // Write your JavaScript code. 5 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2018 Twitter, Inc. 4 | Copyright (c) 2011-2018 The Bootstrap Authors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) .NET Foundation. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Globomantics.IdentityServer/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Initial Users 2 | The database creation logic above will create the following users: 3 | * rr@acme.com / `l00neyTunes!` 4 | * wile@acme.com / `l00neyTunes!` 5 | * kim@mars.com / `to1nfinity!` 6 | * stanley@mars.com / `to1nfinity!` 7 | 8 | ## Setup Notes (Old Way) 9 | * [SQL Server Express](https://www.microsoft.com/en-us/sql-server/sql-server-downloads) 10 | * [Papercut](https://github.com/ChangemakerStudios/Papercut-SMTP) -- This is Windows-only and is replaced in our Docker setup 11 | 12 | ## Preparing Your Workstation for Containers 13 | * [Docker Desktop](https://www.docker.com/products/docker-desktop) 14 | * [Install and Configure Windows Terminal](https://gist.github.com/dahlsailrunner/ec99e195b2a4903748a74df64a1f1a94) 15 | * [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 16 | 17 | 18 | ## SSL With Docker Compose and nginx as Reverse Proxy 19 | https://gist.github.com/dahlsailrunner/679e6dec5fd769f30bce90447ae80081 20 | 21 | ## Local Kubernetes Setup 22 | Just use the Docker Desktop Kubernetes instance (enable it in Settings within Docker Desktop). 23 | 24 | Then here are some handy notes: 25 | https://gist.github.com/dahlsailrunner/1a47b0e38f6e3ba64d4d61835c73b7e2 26 | 27 | ## Excluding Health Checks from Serilog Request Logging 28 | Great blog post by Andrew Lock on this very topic: 29 | https://andrewlock.net/using-serilog-aspnetcore-in-asp-net-core-3-excluding-health-check-endpoints-from-serilog-request-logging/ -------------------------------------------------------------------------------- /docker-compose.dcproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.1 5 | Linux 6 | af4874a2-2371-447e-823d-43687084d905 7 | LaunchBrowser 8 | {Scheme}://localhost:{ServicePort}/.well-known/openid-configuration 9 | globomantics.identityserver 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | reverseproxy: 5 | build: 6 | context: . 7 | dockerfile: nginx/nginx.Dockerfile 8 | depends_on: 9 | - globomantics.identityserver 10 | ports: 11 | - "44395:44395" 12 | networks: 13 | globonet: 14 | aliases: 15 | - "id-local.globomantics.com" 16 | - "www-local.globomantics.com" 17 | 18 | globomantics.identityserver: 19 | image: ${DOCKER_REGISTRY-}globomanticsidentityserver 20 | build: 21 | context: . 22 | dockerfile: Globomantics.IdentityServer/Dockerfile 23 | depends_on: 24 | - globosql 25 | environment: 26 | - ASPNETCORE_URLS=http://*:5000 27 | ports: 28 | - "5000:5000" 29 | networks: 30 | - globonet 31 | 32 | globomantics.ui: 33 | build: 34 | context: . 35 | dockerfile: Globomantics.Core/Dockerfile 36 | environment: 37 | - ASPNETCORE_URLS=http://*:5005 38 | depends_on: 39 | - globosql 40 | ports: 41 | - "5005:5005" 42 | networks: 43 | - globonet 44 | 45 | globomantics.api: 46 | build: 47 | context: . 48 | dockerfile: Globomantics.Api/Dockerfile 49 | environment: 50 | - ASPNETCORE_URLS=http://*:5006 51 | ports: 52 | - "5006:5006" 53 | networks: 54 | - globonet 55 | 56 | globoseq: 57 | image: datalust/seq 58 | restart: unless-stopped 59 | ports: 60 | - "5342:80" 61 | environment: 62 | - ACCEPT_EULA=Y 63 | networks: 64 | - globonet 65 | 66 | globosmtp: 67 | image: rnwood/smtp4dev 68 | restart: always 69 | ports: 70 | - "5010:80" 71 | networks: 72 | - globonet 73 | 74 | globosql: 75 | build: 76 | context: . 77 | dockerfile: sql/sql.Dockerfile 78 | restart: always 79 | ports: 80 | - "1440:1433" 81 | environment: 82 | - ACCEPT_EULA=Y 83 | - SA_PASSWORD=Sqlc0ntainersFTW! 84 | networks: 85 | - globonet 86 | 87 | networks: 88 | globonet: {} -------------------------------------------------------------------------------- /k8s/globo-ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: globo-ingress 5 | spec: 6 | tls: 7 | - hosts: 8 | - id.local.com 9 | secretName: idlocal-tls 10 | rules: 11 | - host: seq.local.com 12 | http: 13 | paths: 14 | - pathType: Prefix 15 | path: / 16 | backend: 17 | service: 18 | name: globoseq-service 19 | port: 20 | number: 80 21 | - host: id.local.com 22 | http: 23 | paths: 24 | - pathType: Prefix 25 | path: /mail/ 26 | backend: 27 | service: 28 | name: globomail-service 29 | port: 30 | number: 80 31 | - pathType: Prefix 32 | path: / 33 | backend: 34 | service: 35 | name: globois4-service 36 | port: 37 | number: 5000 -------------------------------------------------------------------------------- /k8s/globois4.configmap.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: globo-identity-config 5 | data: 6 | Email__SmtpServer: globosmtp-service 7 | Email__SenderAddress: notlistening@globomantics.com -------------------------------------------------------------------------------- /k8s/globois4.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: globomantics-identity 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: globomantics-identity 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: globomantics-identity 14 | spec: 15 | containers: 16 | - name: is4 17 | image: dahlsailrunner/globomantics_is4:latest 18 | envFrom: 19 | - configMapRef: 20 | name: globo-identity-config 21 | - secretRef: 22 | name: globoconn-secrets 23 | livenessProbe: 24 | httpGet: 25 | path: /.well-known/openid-configuration 26 | port: 5000 27 | initialDelaySeconds: 20 28 | timeoutSeconds: 5 29 | periodSeconds: 10 30 | failureThreshold: 3 31 | readinessProbe: 32 | httpGet: 33 | path: /.well-known/openid-configuration 34 | port: 5000 35 | initialDelaySeconds: 20 36 | timeoutSeconds: 5 37 | periodSeconds: 10 38 | failureThreshold: 3 39 | resources: 40 | limits: 41 | memory: "128Mi" 42 | cpu: "200m" 43 | ports: 44 | - containerPort: 5000 45 | 46 | --- 47 | apiVersion: v1 48 | kind: Service 49 | metadata: 50 | name: globois4-service 51 | spec: 52 | selector: 53 | app: globomantics-identity 54 | type: ClusterIP 55 | ports: 56 | - protocol: TCP 57 | port: 5000 58 | targetPort: 5000 -------------------------------------------------------------------------------- /k8s/globoseq-initial.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: globoseq-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: globoseq-app 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: globoseq-app 14 | spec: 15 | containers: 16 | - name: seq 17 | image: datalust/seq:latest 18 | ports: 19 | - containerPort: 5341 20 | - containerPort: 80 21 | env: 22 | - name: ACCEPT_EULA 23 | value: "Y" 24 | --- 25 | apiVersion: v1 26 | kind: Service 27 | metadata: 28 | name: globoseq-service 29 | spec: 30 | selector: 31 | app: globoseq-app 32 | type: NodePort 33 | ports: 34 | - protocol: TCP 35 | port: 80 36 | targetPort: 80 37 | nodePort: 31534 38 | 39 | --- 40 | apiVersion: v1 41 | kind: Service 42 | metadata: 43 | name: globoseq 44 | spec: 45 | clusterIP: None # headless service 46 | selector: 47 | app: globoseq-app 48 | ports: 49 | - protocol: TCP 50 | port: 5341 51 | targetPort: 5341 -------------------------------------------------------------------------------- /k8s/globoseq.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: globoseq-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: globoseq-app 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: globoseq-app 14 | spec: 15 | containers: 16 | - name: seq 17 | image: datalust/seq:latest 18 | ports: 19 | - containerPort: 5341 20 | - containerPort: 80 21 | env: 22 | - name: ACCEPT_EULA 23 | value: "Y" 24 | --- 25 | apiVersion: v1 26 | kind: Service 27 | metadata: 28 | name: globoseq-service 29 | spec: 30 | selector: 31 | app: globoseq-app 32 | type: ClusterIP 33 | ports: 34 | - protocol: TCP 35 | port: 80 36 | targetPort: 80 37 | 38 | --- 39 | apiVersion: v1 40 | kind: Service 41 | metadata: 42 | name: globoseq 43 | spec: 44 | clusterIP: None # headless service 45 | selector: 46 | app: globoseq-app 47 | ports: 48 | - protocol: TCP 49 | port: 5341 50 | targetPort: 5341 -------------------------------------------------------------------------------- /k8s/globosmtp-initial.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: globosmtp 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: globosmtp 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: globosmtp 14 | spec: 15 | containers: 16 | - name: stmp4dev 17 | image: rnwood/smtp4dev:latest 18 | env: 19 | - name: ServerOptions__BasePath 20 | value: "/mail" 21 | ports: 22 | - containerPort: 80 23 | - containerPort: 25 24 | - containerPort: 143 25 | resources: 26 | limits: 27 | memory: "128Mi" 28 | cpu: "200m" 29 | 30 | --- 31 | apiVersion: v1 32 | kind: Service 33 | metadata: 34 | name: globomail-service 35 | spec: 36 | selector: 37 | app: globosmtp 38 | type: NodePort 39 | ports: 40 | - protocol: TCP 41 | port: 80 42 | targetPort: 80 43 | 44 | --- 45 | apiVersion: v1 46 | kind: Service 47 | metadata: 48 | name: globosmtp-service 49 | spec: 50 | clusterIP: None # headless service 51 | selector: 52 | app: globosmtp 53 | ports: 54 | - protocol: TCP 55 | port: 25 56 | targetPort: 25 -------------------------------------------------------------------------------- /k8s/globosmtp.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: globosmtp 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: globosmtp 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: globosmtp 14 | spec: 15 | containers: 16 | - name: stmp4dev 17 | image: rnwood/smtp4dev:latest 18 | env: 19 | - name: ServerOptions__BasePath 20 | value: "/mail" 21 | ports: 22 | - containerPort: 80 23 | - containerPort: 25 24 | - containerPort: 143 25 | resources: 26 | limits: 27 | memory: "128Mi" 28 | cpu: "200m" 29 | 30 | --- 31 | apiVersion: v1 32 | kind: Service 33 | metadata: 34 | name: globomail-service 35 | spec: 36 | selector: 37 | app: globosmtp 38 | type: ClusterIP 39 | ports: 40 | - protocol: TCP 41 | port: 80 42 | targetPort: 80 43 | 44 | --- 45 | apiVersion: v1 46 | kind: Service 47 | metadata: 48 | name: globosmtp-service 49 | spec: 50 | clusterIP: None # headless service 51 | selector: 52 | app: globosmtp 53 | ports: 54 | - protocol: TCP 55 | port: 25 56 | targetPort: 25 -------------------------------------------------------------------------------- /k8s/globosql.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: globodb 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: globodb 9 | replicas: 1 10 | template: 11 | metadata: 12 | labels: 13 | app: globodb 14 | spec: 15 | terminationGracePeriodSeconds: 10 16 | containers: 17 | - name: globodb 18 | image: dahlsailrunner/globomantics_database:latest 19 | ports: 20 | - containerPort: 1433 21 | --- 22 | apiVersion: v1 23 | kind: Service 24 | metadata: 25 | name: globodb-service 26 | spec: 27 | selector: 28 | app: globodb 29 | ports: 30 | - protocol: TCP 31 | port: 1434 32 | targetPort: 1433 33 | nodePort: 31433 34 | type: NodePort 35 | -------------------------------------------------------------------------------- /k8s/id-local.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | default_keyfile = id-local.key 4 | distinguished_name = req_distinguished_name 5 | req_extensions = req_ext 6 | x509_extensions = v3_ca 7 | 8 | [req_distinguished_name] 9 | countryName = US 10 | countryName_default = US 11 | stateOrProvinceName = Minnesota 12 | stateOrProvinceName_default = Minnesota 13 | localityName = St. Paul 14 | localityName_default = St. Paul 15 | organizationName = Globomantics 16 | organizationName_default = Globomantics 17 | organizationalUnitName = Development 18 | organizationalUnitName_default = Development 19 | commonName = id.local.com 20 | commonName_default = id.local.com 21 | commonName_max = 64 22 | 23 | [req_ext] 24 | subjectAltName = @alt_names 25 | 26 | [v3_ca] 27 | subjectAltName = @alt_names 28 | 29 | [alt_names] 30 | DNS.1 = id.local.com -------------------------------------------------------------------------------- /k8s/id-local.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDmTCCAoGgAwIBAgIUH0Of08KqvDbRile65t+RtkM+QIMwDQYJKoZIhvcNAQEL 3 | BQAweDELMAkGA1UEBhMCVVMxEjAQBgNVBAgMCU1pbm5lc290YTERMA8GA1UEBwwI 4 | U3QuIFBhdWwxFTATBgNVBAoMDEdsb2JvbWFudGljczEUMBIGA1UECwwLRGV2ZWxv 5 | cG1lbnQxFTATBgNVBAMMDGlkLmxvY2FsLmNvbTAeFw0yMTAxMDYyMTQ3NTJaFw0y 6 | MjAxMDYyMTQ3NTJaMHgxCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlNaW5uZXNvdGEx 7 | ETAPBgNVBAcMCFN0LiBQYXVsMRUwEwYDVQQKDAxHbG9ib21hbnRpY3MxFDASBgNV 8 | BAsMC0RldmVsb3BtZW50MRUwEwYDVQQDDAxpZC5sb2NhbC5jb20wggEiMA0GCSqG 9 | SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJzg+IubeGBuBQ5E234TwWXOF101fxP7eP 10 | xTJl6Q9ZVYBr0nkqhDB9F0F+497pYD+aoHKhsTMqH0VP/+CanYzleLQ+KxCKM1p8 11 | UyBLJ+knlfLYiOOtZ1U8DBrw6d9ePRoj3X+YQN5fePOLr0yarLc9OWbbVfPvktLq 12 | LAJqhdT7tNwNcW+wwSBs6lhpwxqLy3JfFUVKNqu4JNMZWIBb1YxptkZsN9XxURoL 13 | UfRzX3nMENRL0nCflHqbMMt1ADftRwOg+6WHmAL3PxZKF6Z32RBxkxpCZ1nljY42 14 | 7DUYE7RwJkKYBI6IRPPmeEuzh3c099K/rC/UjNwLm6Juae9CIQl1AgMBAAGjGzAZ 15 | MBcGA1UdEQQQMA6CDGlkLmxvY2FsLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAuMKi 16 | ZneyYaLeSJ6959YOKY3AoxxaOYmNX3//QOTQur3aKXJ6ocHmpng6BVUlvzKY+TvO 17 | fGOxmcdP0pzMlBXhNZ81vV+nfxC085Qjj6h2DM8YbU1FL3HSN7PAO3NOWkvdc/jB 18 | 1hAERNMDFnEb5Gg5ZeQCYIX409NBFwQhscSTGLtiNUwyD+L5Y4SPyVOSSlxaz/y5 19 | TUOIyo5F1Te6hZth6VvYJesKb8xalXcbyQ7XTaeMc/EDy4WzkgN2Np2pKdoKunGs 20 | bkXdYBY1yRZbdZY+GBDWj07S0OKanQpuXzv8HS8gPRXetWND603v5HQKELRnTXIf 21 | tqnE8ofJ5XR3otsdng== 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /k8s/id-local.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJzg+IubeGBuBQ 3 | 5E234TwWXOF101fxP7ePxTJl6Q9ZVYBr0nkqhDB9F0F+497pYD+aoHKhsTMqH0VP 4 | /+CanYzleLQ+KxCKM1p8UyBLJ+knlfLYiOOtZ1U8DBrw6d9ePRoj3X+YQN5fePOL 5 | r0yarLc9OWbbVfPvktLqLAJqhdT7tNwNcW+wwSBs6lhpwxqLy3JfFUVKNqu4JNMZ 6 | WIBb1YxptkZsN9XxURoLUfRzX3nMENRL0nCflHqbMMt1ADftRwOg+6WHmAL3PxZK 7 | F6Z32RBxkxpCZ1nljY427DUYE7RwJkKYBI6IRPPmeEuzh3c099K/rC/UjNwLm6Ju 8 | ae9CIQl1AgMBAAECggEAH12BmJSU66Xh83Coi63cMvWYrUF956cplpTlsmU413+s 9 | iBWcc3k8OBUHPvuXx9oHyLarWmo6M4/MrBRvClj2bywFh6wV1AULSUt6N3QqjtaF 10 | ehY8nNT0sHKJNWyEJReGGpDwpe9fIKOh5tIGK/wwNrnXPLvtQA0n7vGMJpZKdhxt 11 | GsDa7ZDlvEHX2BhCe0kWj91K0gqDsTKdpIEtnG8kNEoQPsk4Ge6XkkBgM6liFTXO 12 | atgD+Ht+uJEQvtTStqSAgcSUtaCut4MxzZwkRG73Bzy5BPdafmwWtedilaQr1Yxe 13 | CDCU2Qt+mbu0OvzqkK+ET1wyP+3WnJoBdAcsMUXAgQKBgQD7iO0HiUlX4BEowxLw 14 | npHnlqpEcmkYYAoSVCy4y1mcFx9pePKgsLlzN+x7qZ/2oTY1uzMHuPNt+pOvia0L 15 | OpnTkZsb+eqIEJjeUfObrkzbuBIXUQA01USYM0yUlxTz4ksc+3nOjtzZCRxmpfHU 16 | H15M/AQXZpKbQimjuqXMrM2A5QKBgQDNYyRomJGWQY/Yy23mYcABSLK23psD/tN0 17 | vcLsd/xzU+O0dy3puancL6JU2P0kzhFEUqKOVfrK4Q8Tx2VuqL5mVu1eOD4IpMEG 18 | 8M2wmOkPHwuvtjtG5cvfft7/uvtlyE8rU+S/obxbrP8OWoLzHcp0pvFKimzk5Cu5 19 | FZD1r3ctUQKBgQDs2bdQRF7Sp0OhHWclOjtrVfzIbO83K5/wOGDQNXMQvtkuSNw2 20 | oZJOwxckLspYwt6346kemXJnWe9c+IgALdMRXGcxBbhpHS/FEGgSbSMkNgSa/gPy 21 | u+tWYd+3fzgUmj5ecRH2haHBoImkwpefRVZXqWr02fosxjVNXgCnZQQxXQKBgHWS 22 | Z2kozU6CQWINMeBL3Knff86HJ53l5g5SAp9zICS0xQitoK7HBaFx8y8299J11BSU 23 | aVGpjmNM6mCcKEhseHIFGORytbAlAAqFFnodTmzFjN8NJmmzaj2KVwV1eCwPuqJG 24 | 6A96+mRQZ8FDtuqNBzQ3zLCrBSMSKqVM3yqFQ2fBAoGBAKw71LqK7mjA276JdDLD 25 | idqNNd3erkdHl+L4+40ufg/dFrLevv0EQv2ezexXYO0cz1VmxwSY+CW66+v1s/fI 26 | hkpaHAZJOLQXRe6CGuA6HiNh0F9HAzfEIA6+wmp25OG3vDuozqqr/V+WKAxhah9T 27 | 39bwpNJPbgNTqhhjAco/RFys 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /k8s/id-local.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/k8s/id-local.pfx -------------------------------------------------------------------------------- /nginx/id-local.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | default_keyfile = id-local.key 4 | distinguished_name = req_distinguished_name 5 | req_extensions = req_ext 6 | x509_extensions = v3_ca 7 | 8 | [req_distinguished_name] 9 | countryName = US 10 | countryName_default = US 11 | stateOrProvinceName = Minnesota 12 | stateOrProvinceName_default = Minnesota 13 | localityName = St. Paul 14 | localityName_default = St. Paul 15 | organizationName = Globomantics 16 | organizationName_default = Globomantics 17 | organizationalUnitName = Development 18 | organizationalUnitName_default = Development 19 | commonName = id-local.globomantics.com 20 | commonName_default = id-local.globomantics.com 21 | commonName_max = 64 22 | 23 | [req_ext] 24 | subjectAltName = @alt_names 25 | 26 | [v3_ca] 27 | subjectAltName = @alt_names 28 | 29 | [alt_names] 30 | DNS.1 = id-local.globomantics.com -------------------------------------------------------------------------------- /nginx/id-local.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDwjCCAqqgAwIBAgIUZxW+rZ/qi+5QPAeYatWbeFFguhEwDQYJKoZIhvcNAQEL 3 | BQAwgYUxCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlNaW5uZXNvdGExETAPBgNVBAcM 4 | CFN0LiBQYXVsMRUwEwYDVQQKDAxHbG9ib21hbnRpY3MxFDASBgNVBAsMC0RldmVs 5 | b3BtZW50MSIwIAYDVQQDDBlpZC1sb2NhbC5nbG9ib21hbnRpY3MuY29tMB4XDTIy 6 | MDEzMTAwMjMzM1oXDTIzMDEzMTAwMjMzM1owgYUxCzAJBgNVBAYTAlVTMRIwEAYD 7 | VQQIDAlNaW5uZXNvdGExETAPBgNVBAcMCFN0LiBQYXVsMRUwEwYDVQQKDAxHbG9i 8 | b21hbnRpY3MxFDASBgNVBAsMC0RldmVsb3BtZW50MSIwIAYDVQQDDBlpZC1sb2Nh 9 | bC5nbG9ib21hbnRpY3MuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC 10 | AQEApHfqZZS7fhNWntoOfZUqGpbpQ2JIpvhRELEBbe2bnUTcMPt6bgORX37dmKlY 11 | lyWcnx89ynsI19q+EMSzdCUFDCiJ/3irwY/zLKjQfLP+R+1tWgBonTvC5j5oNJOj 12 | JE6Izd2zqADhDKUmYKUSyUanAV+ruTFjYxRcSEpqn2GBS8jKies1Yfkc0yPGjc2E 13 | 4R2snpRNLeBDDWrXVms27m5Tkz+lhRA1PRCDxco/G039MM/Qke9v6BblB9qMTfpx 14 | 6nhUjJnmINOzTLbMrkIc1Jih04pfJHqrBQ62r1skx0xdtei9Zkx9tgqmDoD8L8ca 15 | yVd82XWn9zTNnILiS59ZE1ANsQIDAQABoygwJjAkBgNVHREEHTAbghlpZC1sb2Nh 16 | bC5nbG9ib21hbnRpY3MuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQAd6Kdhab251mPI 17 | Z404FHHpT4A7YtW5+PpGfVtvNRxN2/nicP8yAxQWIPuhmEFSEfQSVCvvaPUMch4Z 18 | dOeQbvSUF0NV1r9h99fFAkBLOyTkKgyZzJlQVLLkXMzX+KbqHuuNLHB/NRQn567b 19 | 9SwEipdxtHXAio16yztRsERDryXuCXKHZxblV5QqHtgP2Hr/BpeAJNqKvvsTytrJ 20 | nCO1oPh2whxOlAGLcFDZCCveAOO2t7lTiV+Sg3dxkF4CPNrw/V9woA/St0Jw4npQ 21 | DacCzRKLdyJsDwMV/yczAZGfqD9Q2eEYaQie7C8+yWXkkXqB9dfNUr2zaD+6nx8u 22 | egyNXcZr 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /nginx/id-local.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCkd+pllLt+E1ae 3 | 2g59lSoalulDYkim+FEQsQFt7ZudRNww+3puA5Ffft2YqViXJZyfHz3KewjX2r4Q 4 | xLN0JQUMKIn/eKvBj/MsqNB8s/5H7W1aAGidO8LmPmg0k6MkTojN3bOoAOEMpSZg 5 | pRLJRqcBX6u5MWNjFFxISmqfYYFLyMqJ6zVh+RzTI8aNzYThHayelE0t4EMNatdW 6 | azbublOTP6WFEDU9EIPFyj8bTf0wz9CR72/oFuUH2oxN+nHqeFSMmeYg07NMtsyu 7 | QhzUmKHTil8keqsFDravWyTHTF216L1mTH22CqYOgPwvxxrJV3zZdaf3NM2cguJL 8 | n1kTUA2xAgMBAAECggEAEEHCK5RODCJBN6Z6NDOgW8x69iwq3kZBTRMR/xmzfhIm 9 | abkR2voDTpstsD9dAGO5XYkrBG6w6xU2IFYxHtPh8de3/EajQ5jFAq8VHJ52DgoL 10 | +w97R792fmfAySGmyJnyr9awQXUEyckxR/BJMRgIvfwE72NQXaTPkl24uFRdAW6I 11 | 8xBiexH8OHpx+QSKjjPead9pokR+8WXfJpUftoqyH/OiyjeK8505zkCq/cqPZDNm 12 | eD7d5cFtMVIdyaq+tyizwJ44wVdRwmjlHinl99jvLKkGT0lPTbg0cjhrEsLSn2Q0 13 | 6DqQAx9TO0FMOmhT3YshxT0cXimgRKXoNtfXEedMWQKBgQDSHkr4tcWAhCARHFjI 14 | F/ZzKXI6PR6Otobj/qBRRLpC00nUKjllOHQTQOTOoOeAXkj7n+uK1d8K80KGu60R 15 | HzIbmozZVu6iIHWGlGDel4N9UUgfoAsRx5bdpzDDCIDA7e5T9nCPbsguswWGZTKZ 16 | bqeEKHWUhU2YVNw3GpjMwRLXqwKBgQDIYcXMJVi08yXBel3ppjPEVddnXUTbi7vb 17 | dLWLpzyxkGO6hN+eVlP8WxEtMyB+S0N3TQNBwbTZvBmZJEMWlRP/gz4T1xdKfDbc 18 | EixSo9+sY5WsLjjNhZGvrcratDVjUCAt++7j26NFswi4HWN94bjFijzKrkmXgwAu 19 | 6oXM+8IkEwKBgQCiGo7anFn4EXcv3D++d4ZCSKqAteCaV8VvpmUG7dAJeDrQPZc0 20 | OT6MEBe2NjsENTl3L2SoIuJF73DWw3n86KVe2HhrwP6wA/zHzDeD4z6lcw0CoRWJ 21 | LQN+k9sxzKCQt7+T9V/XuK8mICVWD0LfTphchF5aLBG2QVn4BUP3S8l+qwKBgCE2 22 | A0B4mCE1g3Zzv4jwIPhTeeYJ0VXJ7RLMXyKMT0Tmt4C8cQufJ0BWH5ysMqB7/OyS 23 | +Q02+7ByupNlLTFa9/uLVwiWx6dyuuzyniH8QyAhSTdGWefGUYUaetqQr6CMMSkt 24 | 7kQZrQ/qQnGxfUHp3WPwK280P8I61hbwi8iTmXO9AoGAKiwxv+iRZ47d7IjBVUiB 25 | oU5U1mPS7sI7hnjdNA+oraF34oUnXCW6M+EKubGX6COoFXHtDwpGRimCMrnTvtWm 26 | eSz17Kcc046zLYCgT1J7nZBfU3EhxBOMfdS7s168jPQvLs4lyF2CcshAaJiifU1n 27 | znPbjZWTFKBADJVHSAavrJs= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /nginx/id-local.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/nginx/id-local.pfx -------------------------------------------------------------------------------- /nginx/nginx.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | COPY nginx/nginx.local.conf /etc/nginx/nginx.conf 4 | COPY nginx/id-local.crt /etc/ssl/certs/id-local.globomantics.com.crt 5 | COPY nginx/id-local.key /etc/ssl/private/id-local.globomantics.com.key 6 | COPY nginx/www-local.crt /etc/ssl/certs/www-local.globomantics.com.crt 7 | COPY nginx/www-local.key /etc/ssl/private/www-local.globomantics.com.key -------------------------------------------------------------------------------- /nginx/www-local.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | default_bits = 2048 3 | default_keyfile = www-local.key 4 | distinguished_name = req_distinguished_name 5 | req_extensions = req_ext 6 | x509_extensions = v3_ca 7 | 8 | [req_distinguished_name] 9 | countryName = US 10 | countryName_default = US 11 | stateOrProvinceName = Minnesota 12 | stateOrProvinceName_default = Minnesota 13 | localityName = St. Paul 14 | localityName_default = St. Paul 15 | organizationName = Globomantics 16 | organizationName_default = Globomantics 17 | organizationalUnitName = Development 18 | organizationalUnitName_default = Development 19 | commonName = www-local.globomantics.com 20 | commonName_default = www-local.globomantics.com 21 | commonName_max = 64 22 | 23 | [req_ext] 24 | subjectAltName = @alt_names 25 | 26 | [v3_ca] 27 | subjectAltName = @alt_names 28 | 29 | [alt_names] 30 | DNS.1 = www-local.globomantics.com -------------------------------------------------------------------------------- /nginx/www-local.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxTCCAq2gAwIBAgIUUshAHendMHrqJO3hiacKhnPKwD0wDQYJKoZIhvcNAQEL 3 | BQAwgYYxCzAJBgNVBAYTAlVTMRIwEAYDVQQIDAlNaW5uZXNvdGExETAPBgNVBAcM 4 | CFN0LiBQYXVsMRUwEwYDVQQKDAxHbG9ib21hbnRpY3MxFDASBgNVBAsMC0RldmVs 5 | b3BtZW50MSMwIQYDVQQDDBp3d3ctbG9jYWwuZ2xvYm9tYW50aWNzLmNvbTAeFw0y 6 | MjAxMzEwMDIyNTRaFw0yMzAxMzEwMDIyNTRaMIGGMQswCQYDVQQGEwJVUzESMBAG 7 | A1UECAwJTWlubmVzb3RhMREwDwYDVQQHDAhTdC4gUGF1bDEVMBMGA1UECgwMR2xv 8 | Ym9tYW50aWNzMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEjMCEGA1UEAwwad3d3LWxv 9 | Y2FsLmdsb2JvbWFudGljcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 10 | AoIBAQC+v3CVMCKEfsHPDFnjTVR7w5msnaSRTzc7iygIzQ+xArfz5VZ+zZ52Xnuu 11 | yJFjA1W7ZhtlBzTcHYSkY8Au0YBbMIvG1LFtJvzhMJizSF0LvCj6eykg3q4cSko5 12 | AhKLIDED6ZmfDWHHAGohQPveIgod3fXFdMfdUU81aCWe+UUAAOyojx7xdodSHVPc 13 | uHgJO4qYXzdEk0y1jX1o1kExiNKH2ah5dlRFoGFetjyg/0Lwzk5B5Ini/7Nq2un9 14 | +AAWJ1PNb+TW/l31xc+sEKJaiiTgyx12S0cCoOXW4MPq0ob0o7kXIU9GBGr9tSdh 15 | 9vSD0bQsVDJNwiyvTyfGFR+btG7xAgMBAAGjKTAnMCUGA1UdEQQeMByCGnd3dy1s 16 | b2NhbC5nbG9ib21hbnRpY3MuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBGPBfMa+9S 17 | OgHotFY5np1LHoBi5UZQLQJH6PmSEDY2pGv3K5E8HhlARfDotkN2ZbergYn730at 18 | NLiq8yqP8+qNNQJF1+ytBIvDXCfBbquwZIVjgCHcOu8Q4MJxa68QmO4xiQpatE9o 19 | yWBo7VS6/aYGoyaWjnfg2RR2GbQnvUCVKkTMlW4rdXcNmp9BJzNWXrPgC883GPPl 20 | FHyczf8f3dlP4wAT3nSuBPVbPc72sdkUIPFuqBV0sfp8AWazZfcT4yvuzn3nXK7K 21 | hp1TogOoQYVSLuu9uJPEd5PsXKNslu04rgKcXR8rnVeLvmTfqjGahBbbOSBjxwz/ 22 | q3LJQaLxJQ+z 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /nginx/www-local.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+v3CVMCKEfsHP 3 | DFnjTVR7w5msnaSRTzc7iygIzQ+xArfz5VZ+zZ52XnuuyJFjA1W7ZhtlBzTcHYSk 4 | Y8Au0YBbMIvG1LFtJvzhMJizSF0LvCj6eykg3q4cSko5AhKLIDED6ZmfDWHHAGoh 5 | QPveIgod3fXFdMfdUU81aCWe+UUAAOyojx7xdodSHVPcuHgJO4qYXzdEk0y1jX1o 6 | 1kExiNKH2ah5dlRFoGFetjyg/0Lwzk5B5Ini/7Nq2un9+AAWJ1PNb+TW/l31xc+s 7 | EKJaiiTgyx12S0cCoOXW4MPq0ob0o7kXIU9GBGr9tSdh9vSD0bQsVDJNwiyvTyfG 8 | FR+btG7xAgMBAAECggEAJRPLS4SOwRhujdOFyXQnnuMXhQEjkwdF4jIbdxJ9IVg4 9 | 75S9qmpHihS1j/T2pbtpN8MSQiITeVHXjajCG5enjpIyKVUApAn3D8LFe9vuEjDh 10 | +kZkaTo/t8oNAWXQuvBn9q26qbsNLYR8HLin/La7JrEVa+tWSkPa1LPI1Ez5x5UQ 11 | UhGcPO0lAt4OV7HotUG6ybQ8v3n9p+H3y6v4ZpZyoK7IEplaVftllPX0rfJKKJ3a 12 | h/KWVSGPv4vgqJZXT5DHePFUOWQauzyJSitZI9cyZ4E00iCCrhGZ51bZYoFLk9Bd 13 | QKMIU9goFcmoc7JsN4zlf0RxA0FlNNRrGqR+DnTsAQKBgQDsNZQCY9H6Imn9bKAa 14 | HljYnMbc3ICxua+nKIvcvaV9KNLKPXU99bKvLtbR49cBuhTc2ECAUGscNFfuMWCH 15 | oEbkivoB8Ki7k69NAoyG2GqIfnKHTglE1D5POj7G22EsN9JRvPyrExwxm2EJ+wZv 16 | BE0EBX1qrdMTfjQwkCxzJcUAwQKBgQDOusOuZckBqUIslVkBwUdLNE4MzWu/YTy3 17 | K5OZjfmyHEz3kUg6PJoLzpQLgcuCulTSDqUOgG+jETivd1NJo6IJVubhqNCT6Eg3 18 | fWScdYREAkvMkeUHfrPGmgueD31KKAezfrYyHh5NpEm9mTOaVoVKPia8N2hd+aDi 19 | nHc4ESfKMQKBgB0Ayyar+QlclmUOpG3wkfou7eAKlya7ZQ0CVoIJKzu9+nvope+w 20 | rnsCJlBpSGom3g7r4qeeuDgjWTSfDXo5vNqtEduRIDbAAINVL8oS4qnV1Nw2Qb8Y 21 | zHnP7gtevoS+ae2tZdzfoNOaf4TJNNYG0ioPPoINy+AV2/Smjz6oQZNBAoGAUuXB 22 | oiVevTPKPWaGEpYWqKmIwsl883lih3EJ9wFfp3SByKSRegjjHOjxpMufeASQDsug 23 | lHgcTB+Tw4jt9RGQ4H3gh4zSVv1GODooJjVZnIvvKVE3rhG4tWMAVZmQfDQhInEl 24 | TmOVczz19PmCH9miCWtyzPbK+yQmx7hGdk0qz4ECgYBUalhXIEXObWd5iIJi5cAV 25 | fEZDeuR/hEPJiy4qsOmPJjr97yKsFaGL98u1f7a08zgqfAS84u3T80vgeks4/Zc9 26 | NZCR/aTB3U+WkY7u67neaBFZiXP7nTCFBmxZkWmf+tED+80jMeNKqYPxTPpNo8p5 27 | DfHA5U8a9axpw1I9xwmrtA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /nginx/www-local.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dahlsailrunner/docker-fundamentals/5aa6a5858955d11303cf52c727f513277ae9029c/nginx/www-local.pfx -------------------------------------------------------------------------------- /sql/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #start SQL Server, start the script to create the DB and import the data, start the app 2 | /opt/mssql/bin/sqlservr & ./setup.sh & sleep infinity & wait -------------------------------------------------------------------------------- /sql/setup.sh: -------------------------------------------------------------------------------- 1 | # Wait for SQL Server to be started and then run the sql script 2 | ./wait-for-it.sh globosql:1433 --timeout=0 --strict -- sleep 5s && \ 3 | /opt/mssql-tools/bin/sqlcmd -S localhost -i InitializeGlobomanticsDb.sql -U sa -P "$SA_PASSWORD" -------------------------------------------------------------------------------- /sql/sql.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/mssql/server 2 | 3 | ARG PROJECT_DIR=/tmp/globomantics 4 | RUN mkdir -p $PROJECT_DIR 5 | WORKDIR $PROJECT_DIR 6 | COPY sql/InitializeGlobomanticsDb.sql ./ 7 | COPY sql/wait-for-it.sh ./ 8 | COPY sql/entrypoint.sh ./ 9 | COPY sql/setup.sh ./ 10 | 11 | CMD ["/bin/bash", "entrypoint.sh"] --------------------------------------------------------------------------------