multiple configuration databases for IdentityServer4 - identityserver4

Iam using an identityServer4 with multiple Databases. I could so far use muliple databases with the user-store. I solve it as the follwoing code of a middleware:
public async Task Invoke(HttpContext context)
{
var req = context.Request;
if (req.Path == "/Account/Login" && req.Method.Equals("POST"))
{
if (req.Form.Keys.Contains("Input.Database") == false)
{
throw new InvalidOperationException("No database key was sent with this request: " + req.Path);
}
var lDatabasKey = req.Form["Input.Database"];
_configuration["ConnectionStrings:default"] = _configuration[$"ConnectionStrings:{lDatabasKey}"];
}
the configuration Object get updated, so the value ConnectionString:default get updated with the connectionstring i need to use.
This concept unfortunatley not working the the configuration database, which inistalised in the ConfigureServices in Startup.cs:
string connectionString = Configuration.GetConnectionString("default");
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedEmail = false;
})
.AddEntityFrameworkStores<IdentityUserDbContext>()
.AddDefaultTokenProviders().AddClaimsPrincipalFactory<CentralHubClaimsPrincipalFactory>();
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Logout";
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
CookieSlidingExpiration = true
};
})
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
}).AddAspNetIdentity<ApplicationUser>()
.AddProfileService<AspNetIdentityProfileService>();
using breaking point i can see that the connectionString:default in the middleware has correct value of the database i want to use. but it still uses the default connectionString which has been saved in the previous method in startup.cs.
So is it possible to use multiple configuration databases for the identityServer?

One option is to create your own EntityFramework configuration backend for IdentityServer by taking the existing source code and hack the queries made.
Then use a clientID prefix as the "database" identifier/selector, like
A0000-A9999 -> goes to Database A
B0000-B9999 -> goes to Database B
C0000-C9999 -> goes to Database C
or use a clientID like:
AAA:XXX where AAA is the client/DB identifier and XXX is the client within that database.
To select the database/connection string to use. To "fool" IdentityServer to believe that there is only one "database".
Having a structured clientID also makes it easier to debug and reason about the system.

Related

Is it possible for an Asp.Net Core Web Application to be integrated with local storage?

I have the below working on local host. However when I publish to azure the connection to my network doesn't work? I guess, this is obvious - my web app doesn't have connection to my local network. My question is, is there a way to allow a connection?
try
{
var path = "//192.168.49.14/Data/18 Customer Requests/Customer Request System/Request Letters/";
//Fetch all files in the Folder (Directory).
string[] filePaths = Directory.GetFiles(Path.Combine(path));
//Copy File names to Model collection.
var localFileList = new List<FileData>();
var assocFiles = new List<FileData>();
var linkedFiles = new List<FileData>();
assocFiles = localFileList.Where(x => x.FileName.Contains(id.ToString())).ToList();
foreach (var filePath in filePaths)
{
localFileList.Add(new FileData { FileName = Path.GetFileName(filePath) });
}
assocFiles = localFileList.Where(x => x.FileName.Contains(id.ToString())).ToList();
foreach (var item in assocFiles)
{
linkedFiles.Add(new FileData { FileName = Path.GetFileName(item.FileName) });
}
ViewBag.localFiles = linkedFiles;
}
catch
{
;
}
return View(Complaint);

Error connecting to http://localhost:8000/.well-known/openid-configuration/jwks. Object reference not set to an instance of an object

I host my identity server use address http://10.2.5.90:8000 and use nginx map https://10.2.5.90:8888 to http://10.2.5.90:8000.
When i tried to request discovery document like quickstart in client, "Error connecting to http://localhost:8000/.well-known/openid-configuration/jwks. Object reference not set to an instance of an object.." occurred.
I tried to change Issuer to https address and used customized DiscoveryDocumentRequest. But it was not work.
When I remove the nginx and access http://10.2.5.90:8000, It worked well.
IdentityServer:Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// ...other codes
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.IssuerUri = "https://10.2.5.90:8888";
});
// ...other codes
}
Client: Program.cs
private static async Task<string> GetAccessTokenAsync()
{
var client = new HttpClient();
var req = new DiscoveryDocumentRequest
{
Address = "https://10.2.5.90:8888",
Policy = new DiscoveryPolicy
{
ValidateIssuerName = false,
ValidateEndpoints = false,
}
};
var disco = await client.GetDiscoveryDocumentAsync(req);
if (disco.IsError)
{
Console.WriteLine(disco.Error);
// output: Error connecting to http://localhost:8000/.well-known/openid-configuration/jwks. Object reference not set to an instance of an object..
return null;
}
// ...other codes
}
Edit:
I changed the code when config identity server and it works when running discovery.
var builder = services.AddIdentityServer(options =>
{
options.PublicOrigin = "https://10.2.5.90:8888";
});
However, I still couldn't access my api. The error is Exception occurred while processing message.IDX20803: Unable to obtain configuration from: 'http://localhost:8000/.well-known/openid-configuration' and I'm researchig the solution
You have to change de Authority property in your api. The api needs to access to the discovery endpoint through nginx (port 8888):
services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.Audience = "api1";
options.RequireHttpsMetadata = true;
options.Authority = "https://10.2.5.90:8888";
});
If you have a public IP and your backend farm use internal uris you can adjust your host uri data in the middleware. Try to put this middleware in the first position:
app.Use(async (context, next) =>
{
context.Request.Scheme = "https";
context.Request.Host = new HostString("10.2.5.90.8888");
context.Request.PathBase = "yourApplicationPathBase";
await next.Invoke();
});
Of course, you have to parameterize this strings by environment in your configuration.

AddConfigurationStore using Oracle.EntityFrameworCore(2.18.0-beta3) OracleException: ORA-00942: table or view does not exist

I am using EntityFramework Core for configuration and operational data using Oracle.EntityFrameworkCore(2.18.0-beta3) but receive "OracleException: ORA-00942: table or view does not exist".
Oracle.EntityFrameworkCore(2.18.0-beta3) is working as I can use "MVC Controller with Views, using Entity Framework" to scaffold a new Controller which will create and edit Oracle tables (Clients and IdentityResources Controllers were created).
Startup.cs ConfigureServices contains the following configuration:
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
b.UseOracle(connectionString);
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
b.UseOracle(connectionString);
options.EnableTokenCleanup = true;
});
The Welcome to IdentityServer4 (version 2.4.0.0) page shows, and will route to the controller options, but the "discover document", (http://localhost:5000/.well-known/openid-configuration), returns
"OracleException: ORA-00942: table or view does not exist".
Got this to work with Oracle.EntityFrameworkCore (2.19.0-beta4). A couple of things that I learned along the way:
1) Many instances of Oracle adhere to the SQL-92 standard which limits objects (including table names and column names) to 30 characters; several of the default IdentityServer4 "Client" table column names exceed 30 characters. The EF migration was modified to adapt the column name character limit.
b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
.HasColumnName("AlwaysIncludeUserClaimsInIdTok");
2) Oracle handles incrementing primary keys differently than SQLServer. The EF migration Oracle:ValueGenerationStrategy property is used for all primary keys.
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("Oracle:ValueGenerationStrategy", OracleValueGenerationStrategy.IdentityColumn);
3) Oracle table names are not case sensitive if they are created all uppercase; if they are created mixed case, they are case sensitive. I was able to get IdentityServer4 working with Oracle using default IdentityServer4 table names. However, I chose to change the table names to all uppercase by changing the EF properties to upper case:
migrationBuilder.CreateTable(name: "IS4_CLIENT",
b.ToTable("IS4_CLIENT"),
principalTable: "IS4_CLIENT",
The IdentityServer4 configuration store properties needed to be changed to match the altered upper case table names. The following is the extension class that was used to configure IdentityServer4 AddConfigurationStore and the AddOperationalStore.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Oracle.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using IdentityServer4.EntityFramework.Entities;
namespace is4ef.Extensions
{
public static class Is4BuilderExtensions
{
public static string IdentityResource { get; private set; }
public static IIdentityServerBuilder AddIs4ConfigurationStore(
this IIdentityServerBuilder builder, string connectionString)
{
string assemblyNamespace = typeof(Is4BuilderExtensions)
.GetTypeInfo()
.Assembly
.GetName()
.Name;
builder
.AddConfigurationStore(options => {
options.ConfigureDbContext = b =>
b.UseOracle(connectionString, optionsBuilder =>
optionsBuilder.MigrationsAssembly(assemblyNamespace)
.UseOracleSQLCompatibility("12"));
options.DefaultSchema = "X13663";
options.ApiClaim.Name = "IS4_AIPCLAIM";
options.ApiResourceProperty.Name = "IS4_APIPROPERTY";
options.ApiResource.Name = "IS4_APIRESOURCE";
options.ApiScopeClaim.Name = "IS4_APISCOPECLAIM";
options.ApiScope.Name = "IS4_APISCOPE";
options.ApiSecret.Name = "IS4_APISECRET";
options.ClientClaim.Name = "IS4_CLIENTCLAIM";
options.ClientCorsOrigin.Name = "IS4_CLIENTCORSORIGIN";
options.ClientGrantType.Name = "IS4_CLIENTGRANTTYPE";
options.ClientIdPRestriction.Name = "IS4_CLIENTIDPRESTRICTION";
options.ClientPostLogoutRedirectUri.Name = "IS4_CLIENTPOSTLOGOUTREDIRECTURI";
options.ClientProperty.Name = "IS4_CLIENTPROPERTY";
options.ClientRedirectUri.Name = "IS4_CLIENTREDIRECTURI";
options.Client.Name = "IS4_CLIENT";
options.ClientScopes.Name = "IS4_CLIENTSCOPE";
options.ClientSecret.Name = "IS4_CLIENTSECRET";
options.IdentityClaim.Name = "IS4_IDENTITYCLAIM";
options.IdentityResourceProperty.Name = "IS4_IDENTITYPROPERTY";
options.IdentityResource.Name = "IS4_IDENTITYRESOURCE";
})
.AddOperationalStore(options => {
options.ConfigureDbContext = b =>
b.UseOracle(connectionString, optionsBuilder =>
optionsBuilder.MigrationsAssembly(assemblyNamespace)
.UseOracleSQLCompatibility("12"));
options.DefaultSchema = "X13663";
options.DeviceFlowCodes.Name = "IS4_DEVICECODE";
options.PersistedGrants.Name = "IS4_PERSISTEDGRANT";
});
return builder;
}
}
}

Identity Server with EF not storing tokens to database

I have setup Identity Server using EF. How do I configure or in code setup the server to store the token in the database. When the cleanup process runs, it consistently logs 0 tokens available for cleanup.
Any help would be appreciated.
services.AddTransient<IResourceOwnerPasswordValidator, CustomSessionValidator>()
.AddTransient<IAuthRepository, CustomAuthRepository>();
services.AddIdentityServer()
.AddSigningCredential(certificates[0])
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
});
services.AddDbContext<CustomApplicationDbContext>(options => options.UseSqlServer(connectionString));
Client config. extracting from DB and displaying in code for completeness.
new Client
{
ClientId = "",
AllowedGrantTypes =
{
GrantType.Hybrid,
GrantType.ResourceOwnerPassword,
},
ClientSecrets =
{
new Secret("".Sha256())
},
AllowedScopes = { "scope1",
"offline_access" },
AllowOfflineAccess = true,
RefreshTokenExpiration = TokenExpiration.Absolute,
AbsoluteRefreshTokenLifetime = 3600,
AccessTokenLifetime = 3600
},
Update: Thanks to tips. The documentation does not state that only the refresh token is stored. I was expecting the access token to be stored. Once configured the refresh token to the correct expiration time, the cleanup process started working.
Thanks
Greg

Getting ArgumentOutOfRangeException error Idenity Server4

We are using Entity framework core with Identity server4 and getting the ArgumentOutOfRangeException when calling the token endpoint via code. Here is our ConfigurationServices method in Identity server project:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
string connectionString = Configuration.GetConnectionString("IdentityServer");
var rsaProvider = new RSACryptoServiceProvider(512);
SecurityKey key = new RsaSecurityKey(rsaProvider);
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials
(key, SecurityAlgorithms.RsaSha512Signature);
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer()
.AddSigningCredential(credentials)
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
}) // this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
// options.EnableTokenCleanup = true;
// options.TokenCleanupInterval = 30;
});
// Add S3 to the ASP.NET Core dependency injection framework.
services.AddAWSService<Amazon.S3.IAmazonS3>();
}
Here is our client application that calling identity server project("http://localhost:3000/"):
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Get(string client, string secret)
{
IActionResult result = null;
//discover endpoints from metadata
var disco = await DiscoveryClient.GetAsync("http://localhost:3000/");
if (disco.IsError)
{
result = NotFound(disco.Error);
return result;
}
//request token
var tokenClient = new TokenClient(disco.TokenEndpoint, client, secret);
var tokenResponse = await tokenClient.RequestClientCredentialsAsync(scope: "sup");
if (tokenResponse.IsError)
{
result = NotFound(tokenResponse.Error);
}
result = Ok(tokenResponse.Json);
return result;
}
Here is error we have got:

Resources