Skip to content

Instantly share code, notes, and snippets.

@sefatanam
Created December 23, 2024 22:43
Show Gist options
  • Save sefatanam/a3b65d039413afb292c98795dc6973a7 to your computer and use it in GitHub Desktop.
Save sefatanam/a3b65d039413afb292c98795dc6973a7 to your computer and use it in GitHub Desktop.
OneClient Backend Changes
sClLQOkek3PlsAbDteBRX+F69oDNnaAlyyRgcKPdAtQU0JuN5Pmx5iD4/rMQXSZ9uCHLKKZA/b9Nk/H9JVsc7BBb5yLcul8GOCoIAHJzj+Q55LfS7e20HP+hkyzd6fhszW+f8pihxeyM6YraoZTG9sskGhwUAMuIISKaClAhXMcEn/nf88SBlJtBgegICcSdrmm/30b6+vER+UpNl31J07soV6hLfECnLepyizSX22A=

If you want to run using dotnet CLI like dotnet run you have to add this profile in launchSettings.json.

 "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:7076",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
using Autofac.Extensions.DependencyInjection;
using Hjson;
using metasonic.Universal.Constant.Const;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System.IO;
using System.Text;
namespace metasonic.Universal.Integrator
{
public class Program
{
public static void Main(string[] args)
{
var path = Directory.GetCurrentDirectory() + "/" + AppConstant.APPSETTING_FILE;
MemoryStream jsonStream = new MemoryStream(Encoding.ASCII.GetBytes(HjsonValue.Load(path).ToString()));
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonStream(jsonStream).Build();
//.AddJsonFile(AppConstant.APPSETTING_FILE, optional: false, reloadOnChange: true).Build();
jsonStream.Dispose();
CreateHostBuilder(args, configuration)
.Build().Run();
}
public static IWebHostBuilder CreateHostBuilder(string[] args, IConfiguration config) =>
WebHost.CreateDefaultBuilder(args)
.UseConfiguration(config)
.ConfigureServices(services => services.AddAutofac())
.UseStartup<Startup>();
}
}
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper;
using Castle.DynamicProxy;
using metasonic.Universal.BusinessLayer.ServiceContracts;
using metasonic.Universal.BusinessLayer.Services;
using metasonic.Universal.Common;
using metasonic.Universal.Common.Helper;
using metasonic.Universal.Common.Resources;
using metasonic.Universal.Constant.Const;
using metasonic.Universal.Constant.Enums;
using metasonic.Universal.Context;
using metasonic.Universal.Doc;
using metasonic.Universal.Doc.Helper;
using metasonic.Universal.Doc.Interface;
using metasonic.Universal.Integrator.Autofac;
using metasonic.Universal.Integrator.Filters;
using metasonic.Universal.Integrator.Helper;
using metasonic.Universal.Integrator.Helper.Cache;
using metasonic.Universal.Integrator.Middleware;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Hjson;
//SAML
using ITfoxtec.Identity.Saml2;
using ITfoxtec.Identity.Saml2.Schemas.Metadata;
using ITfoxtec.Identity.Saml2.MvcCore.Configuration;
using metasonic.Universal.ExternalStorage;
using Microsoft.AspNetCore.Http.Features;
using metasonic.Universal.Process.Helper;
//END SAML
namespace metasonic.Universal.Integrator
{
public class Startup
{
public Startup(IConfiguration Configuration)
{
this.Configuration = Configuration;
}
public IConfiguration Configuration { get; set; }
public ILifetimeScope AutofacContainer { get; private set; }
private byte[] _appsettingsHash { get; set; }
private int dbType { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var logConfiguration = new LoggerConfiguration().ReadFrom.Configuration(Configuration);
Log.Logger = logConfiguration.CreateLogger();
services.AddSingleton(Log.Logger);
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Version = "v1",
Title = "Universal Integrator Service",
});
c.CustomSchemaIds(type => type.ToString());
});
services.AddSingleton<LocalizeManager>();
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddSingleton(provider => new MapperConfiguration(cfg =>
{
cfg.AddProfile(new EntityDTOMapper(provider.GetService<LocalizeManager>()));
}).CreateMapper());
//SAML
if (Configuration["enableSAMLAuthentication"].ToLower() == "true")
{
services.Configure<Saml2Configuration>(Configuration.GetSection("Saml2"));
services.Configure<Saml2Configuration>(saml2Configuration =>
{
saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);
try
{
var entityDescriptor = new EntityDescriptor();
entityDescriptor.ReadIdPSsoDescriptorFromUrl(new Uri(Configuration["Saml2:IdPMetadata"]));
if (entityDescriptor.IdPSsoDescriptor != null)
{
saml2Configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.First().Location;
//saml2Configuration.SingleLogoutDestination = entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.First().Location;
saml2Configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
}
else
{
throw new Exception("IdPSsoDescriptor not loaded from metadata.");
}
}
catch(Exception)
{
}
});
services.AddSaml2();
}
//END SAML
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration[AppConstant.JWK_SECURITYKEY]))
};
});
services.AddAuthorization(option =>
{
option.AddPolicy("AdminRole", policy => policy.RequireClaim("IsAdmin", "1"));
option.AddPolicy("SuperUserRole", policy => policy.RequireClaim("IsSuperUser", "1"));
});
services.AddMemoryCache();
services.AddControllers();
services.AddSingleton<AppConfigSetting>();
services.AddSingleton<ICacheHelper, MemoryCacheHelper>();
services.AddScoped<IDocLoginService, DocLoginService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IUserContext, UserContext>();
services.AddScoped<CommonHelper>();
services.AddScoped<PermissionHelper>();
services.AddScoped<AuthenticationHelper>();
services.AddScoped<GlobalSearchService>();
services.AddScoped<RestAPIHelper>();
services.AddScoped<ProcessApiWebService>();
services.AddScoped<DocumentTileHelper>();
services.AddScoped<SharepointStorage>();
services.AddControllers();
var ConnectionStringEncrypted = Convert.ToBoolean(Configuration[AppConstant.IS_CONNECTIONSTRING_ENCRYPTED]);
var ConnectionString = Configuration.GetConnectionString(AppConstant.UNIVERSAL_CONNECTIONSTRING);
ConnectionString = ConnectionStringEncrypted ? EncryptionHelper.Decrypt(ConnectionString, AppConstant.ENCRYPT_DECRYPT_CONN_STRING_KEY) : ConnectionString;
dbType = Convert.ToInt16(Configuration[AppConstant.DBType]);
if (dbType == (int)DBType.SQL)
{
services.AddDbContext<UniversalClientDbContext>(options =>
{
options.UseSqlServer(ConnectionString, b => b.MigrationsAssembly("metasonic.Universal.Integrator"));
}, ServiceLifetime.Transient
);
}
else if (dbType == (int)DBType.Oracle)
{
services.AddDbContext<UniversalClientDbContext>(options =>
{
options.UseOracle(ConnectionString,
b => b.MigrationsAssembly("metasonic.Universal.Integrator").UseOracleSQLCompatibility("11"));
}, ServiceLifetime.Transient
);
}
else if (dbType == (int)DBType.Postgre)
{
services.AddDbContext<UniversalClientDbContext>(options =>
{
options.UseNpgsql(ConnectionString, b => b.MigrationsAssembly("metasonic.Universal.Integrator"));
}, ServiceLifetime.Transient );
}
DocUrlHelper.DisableSignatureValidation = string.IsNullOrEmpty(Configuration[AppConstant.DISABLE_SIGNATURE_VALIDATION_KEY]) ? true : Configuration[AppConstant.DISABLE_SIGNATURE_VALIDATION_KEY].ToUpper() == "TRUE";
services.AddScoped<IInterceptor, DocInterceptor>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<IUserTilePreferenceService, UserTilePreferenceService>();
services.AddScoped<IUserService, UserService>();
services.AddScoped<IRolePermissionService, RolePermissionService>();
services.AddScoped<IMenuService, MenuService>();
services.AddScoped<IModuleService, ModuleService>();
services.AddScoped<IConfigurationService, ConfigurationService>();
services.AddScoped<IDocumentSharePointService, DocumentSharePointService>();
services.AddScoped<IUserTileConfigurationService, UserTileConfigurationService>();
services.AddScoped<IUserSearchSettingService, UserSearchSettingService>();
services.AddScoped<IUserPreferenceService, UserPreferenceService>();
services.AddScoped<IUserGridPreferenceService, UserGridPreferenceService>();
services.AddScoped<IUserDashboardService, UserDashboardService>();
services.AddScoped<ITileTypeFactory, TileTypeFactory>();
services.AddScoped<IUserPinnedItemService, UserPinnedItemService>();
services.AddScoped<IRoleService, RoleService>();
services.AddScoped<IMasterChildSettingService, MasterChildSettingService>();
services.AddScoped<IUserSearchCriteriaService, UserSearchCriteriaService>();
services.AddScoped<IInboxSettingService, InboxSettingService>();
services.AddScoped<IDocumentTemplateSettingService, DocumentTemplateSettingService>();
services.AddScoped<IPublicFilterService, PublicFilterService>();
services.AddOptions();
services.AddCors(options =>
{
options.AddPolicy("AllowEverything", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddScoped<ConfigurationOnActionFilter>();
services.Configure<FormOptions>(x =>
{
x.ValueLengthLimit = int.MaxValue;
x.MultipartBodyLengthLimit = int.MaxValue;
x.MultipartHeadersLengthLimit = int.MaxValue;
});
//CreateGraphClient();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
if (dbType == (int)DBType.Postgre)
{
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
}
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("AllowEverything");
app.UseAuthentication();
app.UseSaml2(); //SAML
app.UseAuthorization();
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseMiddleware<JwtMiddleware>();
var serviceProvider = app.ApplicationServices;
var cacheHelper = serviceProvider.GetService<ICacheHelper>();
string systemCulture = System.Globalization.CultureInfo.CurrentCulture.Name;
cacheHelper.Put(AppConstant.SYSTEM_CULTURE, systemCulture);
//cacheHelper.Put(AppConstant.SYSTEM_CULTURE, "de-DE");
Log.Logger.Information("StartUp -> Current system culture is :" + systemCulture);
app.Use(async (context, next) =>
{
context.Response.Headers.Add("Access-Control-Max-Age", "600");
var userLangs = context.Request.Headers["CultureInfo"].ToString();
var firstLang = userLangs.Split(',').FirstOrDefault();
var lang = "en-US"; //default
switch (firstLang)
{
case "de-DE":
lang = "de-DE"; //allowed
break;
}
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(lang);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
await next.Invoke();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("../swagger/v1/swagger.json", "Universal Client Integrator API");
});
MapperHelper.Mapper = serviceProvider.GetService<IMapper>();
EncryptConnectionStrings(env);
_appsettingsHash = EncryptionHelper.ComputeHash(AppConstant.APPSETTING_FILE);
ChangeToken.OnChange(
() => Configuration.GetReloadToken(),
(state) => InvokeConfigurationChanged(state),
env);
}
private void InvokeConfigurationChanged(IWebHostEnvironment env)
{
Log.Information("App settings changes detected.");
byte[] appsettingsHash = EncryptionHelper.ComputeHash(AppConstant.APPSETTING_FILE);
if (!_appsettingsHash.SequenceEqual(appsettingsHash))
{
_appsettingsHash = appsettingsHash;
EncryptConnectionStrings(env, true);
Log.Information("Configuration is reloaded.");
}
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new AutofacModule());
}
#region private methods
/// <summary>
/// Encrypt Connection Strings
/// </summary>
/// <param name="env"></param>
private void EncryptConnectionStrings(IWebHostEnvironment env, bool isAppSettingChange = false)
{
try
{
var appSettingFilePhysicalPath = env.ContentRootFileProvider.GetFileInfo(AppConstant.APPSETTING_FILE).PhysicalPath;
var appSettingsObject = (WscJsonObject)HjsonValue.Load(appSettingFilePhysicalPath, new HjsonOptions() { KeepWsc = true }).Qo();
bool isConnectionStringChange = false;
var IsConnectionStringEncrypted = string.IsNullOrEmpty(appSettingsObject.Qstr(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED)) ? false : Convert.ToBoolean(appSettingsObject.Qstr(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED));
if (!IsConnectionStringEncrypted)
{
if (!isAppSettingChange)
{
var connectionSection = appSettingsObject.Qo(AppConstant.CONNECTION_STRING);
if (connectionSection != null && connectionSection.TryGetValue(AppConstant.UNIVERSAL_CONNECTIONSTRING, out JsonValue connString))
{
int isConnectionStringEncryptKeyIndex = appSettingsObject.Order.IndexOf(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED);
connectionSection[AppConstant.UNIVERSAL_CONNECTIONSTRING] = EncryptionHelper.Encrypt(connString, AppConstant.ENCRYPT_DECRYPT_CONN_STRING_KEY);
appSettingsObject[AppConstant.IS_CONNECTIONSTRING_ENCRYPTED] = true;
if (isConnectionStringEncryptKeyIndex == -1)
{
insertKeyIntoAppSettingFile(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED, AppConstant.CONNECTION_STRING, appSettingsObject);
}
isConnectionStringChange = true;
}
}
else
{
Log.Information("Connection string changes is applied only after application restart. Please restart the application if you want to change application connection string.");
}
}
bool anyIncomingEmailChanges = EncyptIncomingEmailConnectionStrings(appSettingsObject);
//bool isSharepointConfigurationChange = EncryptSharepointConfiguration(appSettingsObject);
if (isConnectionStringChange || anyIncomingEmailChanges)
{
SaveAppSettingChanges(appSettingFilePhysicalPath, appSettingsObject);
}
}
catch (Exception ex)
{
Log.Error(ex, ex.Message);
}
}
/// <summary>
/// Save AppSetting changes
/// </summary>
/// <param name="appSettingFilePhysicalPath"></param>
/// <param name="appSettingsObject"></param>
private void SaveAppSettingChanges(string appSettingFilePhysicalPath, WscJsonObject appSettingsObject)
{
HjsonValue.Save(appSettingsObject, appSettingFilePhysicalPath, new HjsonOptions() { KeepWsc = true });
}
/// <summary>
/// Add new key IsConnectionStringEncrypted into appConfig file
/// </summary>
/// <param name="key"></param>
/// <param name="wscJsonObject"></param>
private void insertKeyIntoAppSettingFile(string newKey, string placementKey, WscJsonObject wscJsonObject)
{
int connectionStringSectionindex = wscJsonObject.Order.IndexOf(placementKey) + 1;
wscJsonObject.Order.Insert(connectionStringSectionindex, newKey);
}
private bool EncyptIncomingEmailConnectionStrings(WscJsonObject appSettingsObject)
{
bool anyChanges = false;
var incomingEmailObj = (WscJsonObject)appSettingsObject.Qo(AppConstant.INCOMING_EMAIL_CONFIG);
if (incomingEmailObj != null && incomingEmailObj.Keys.Count > 0)
{
for (int i = 0; i < incomingEmailObj.Keys.Count; i++)
{
var key = incomingEmailObj.Keys.ToArray()[i];
var configObj = (WscJsonObject)incomingEmailObj.Qo(key);
var IsConnectionStringEncrypted = string.IsNullOrEmpty(configObj.Qstr(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED)) ? false :
Convert.ToBoolean(configObj.Qstr(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED));
var connectionString = configObj.Qstr(AppConstant.INCOMINGE_MAIL_CONNECTIONSTRING);
if (!IsConnectionStringEncrypted && !string.IsNullOrEmpty(connectionString))
{
configObj[AppConstant.INCOMINGE_MAIL_CONNECTIONSTRING] = EncryptionHelper.Encrypt(connectionString, AppConstant.ENCRYPT_DECRYPT_CONN_STRING_KEY);
int isConnectionStringEncryptKeyIndex = configObj.Order.IndexOf(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED);
configObj[AppConstant.IS_CONNECTIONSTRING_ENCRYPTED] = true;
if (isConnectionStringEncryptKeyIndex == -1)
{
insertKeyIntoAppSettingFile(AppConstant.IS_CONNECTIONSTRING_ENCRYPTED, AppConstant.INCOMINGE_MAIL_CONNECTIONSTRING, configObj);
}
anyChanges = true;
}
}
}
return anyChanges;
}
//private void CreateGraphClient()
//{
// string ClientId = "cd771206-9370-437d-afc2-041890b2630c";
// string TenantId = "18fdbfe4-3a43-45f2-912f-6a88c76f7c49";
// string[] Scopes = new String[1] { "https://graph.microsoft.com/.default" };
// string password = "system123#";
// SecureString securePassword = new SecureString();
// foreach (char c in password)
// { securePassword.AppendChar(c); }
// IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
// .Create(ClientId)
// .WithTenantId(TenantId)
// .Build();
// UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication, Scopes);
// GraphServiceClient graphClient = new GraphServiceClient(authProvider);
// User me = graphClient.Me.Request()
// .WithUsernamePassword("[email protected]", securePassword)
// .GetAsync().Result;
// EncryptionHelper.graphClient = graphClient;
//}
#endregion private methods
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment