Can't specify database name during jdbc connection - sql-server

I'm using Spring MVC 4.3 to connect to a Miscorosft SQL Server with JDBC. My SQL Server have some databases, I'm trying to connect to TEST_DB one. But when I try to establish connection I receive this error:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The server principal "testuser" is not able to access the database "A_Source_Db" under the current security context.
A_Source_Db is the first db in alphabetical order, so I think I can't specify the db name to connect to.
I use Hibernate too and Spring Data. These are some files I think are useful
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.test.domain")
#PropertySource("classpath:db.properties")
#ComponentScan({"com.test", "com.test.domain.repository"})
public class HibernateConfig {
#Autowired
private Environment env;
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("mssql.driver"));
dataSource.setUrl(env.getRequiredProperty("mssql.url"));
dataSource.setUsername(env.getRequiredProperty("mssql.user"));
dataSource.setPassword(env.getRequiredProperty("mssql.password"));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan("com.test.domain");
entityManagerFactoryBean.setJpaProperties(hibProperties());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(DIALECT, "org.hibernate.dialect.SQLServerDialect");
properties.put(SHOW_SQL, true);
return properties;
}
}
This is my db.properties
mssql.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
mssql.url=jdbc:sqlserver://192.168.1.100:1433;databaseName=TEST_DB
mssql.user=testuser
mssql.password=testPwd

Related

How connect to an existing Azure SQL database with ASP.NET CORE MVC using Entity Framework Core with migrations?

I have an app using Azure App Services with SQL server and SQL database that are connect to my web app on asp MVC. I've used Distributed Sql Server Cache as a table on my database and so far everything is working well and connected to each other.
Now I want to do two things:
Add entity framework to my app (I already have the database and
connection string)
Run migration – after I've published my app (If I've added for a
example new line or new
table, now I have new version)
I'm not sure how to do those things , I've looked up on many guides and couldn't find an answer. I found a post similar to mine – but using azure functions - here
. I would appreciate it if someone can help me with the steps that I need to follow (like they did in that post) to get entity framework and the migration.
Here is my code:
Program.cs-
using Microsoft.Extensions.Azure;
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
if(!builder.Environment.IsDevelopment())
builder.Configuration.AddAzureKeyVault(new Uri(Environment.GetEnvironmentVariable("VaultUri")), new DefaultAzureCredential());
builder.Services.AddControllersWithViews();
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(builder.Configuration["storage:blob"], preferMsi: true);
clientBuilder.AddQueueServiceClient(builder.Configuration["storage:queue"], preferMsi: true);
});
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString("db");
options.SchemaName = "dbo";
options.TableName = "_Cache";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
Home Controller:
namespace WebAppAzure.Controllers
{
public class HomeController : Controller
{
private readonly BlobServiceClient storage;
private readonly ILogger<HomeController> logger;
private readonly IDistributedCache cache;
public HomeController(BlobServiceClient storage, ILogger<HomeController> logger,
IDistributedCache cache)
{
this.storage = storage;
this.logger = logger;
this.cache = cache;
}
public IActionResult Index()
{
var containerClient = storage.GetBlobContainerClient("public");
var blob = containerClient.GetBlobClient("image.jpeg");
var model = blob.Uri.ToString();
return View(model: model);
}
public IActionResult Privacy()
{
var stringModel = DateTime.Now.ToString();
cache.SetString("name", stringModel);
return View(model: $"SET: {stringModel}");
}
public IActionResult About()
{
var stringModel = cache.GetString("name");
return View(model: $"GET: {stringModel}");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Add entity framework to my app (I already have the database and connection string)
Use below code for add Entity framework and upload to azure app service and run migration command to migrate database.
DBcontext file in project.
using Microsoft.EntityFrameworkCore;
using WebApplication_72783922.Entity;
namespace WebApplication_72783922
{
public class DbConnectionEntity : DbContext
{
public DbConnectionEntity()
{
}
//string connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:dbcon").ToString();
public DbConnectionEntity(DbContextOptions<DbConnectionEntity> options)
: base(options)
{
}
public virtual DbSet<Users> users { get; set; }
public virtual DbSet<department> Departments { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=xxxx;Initial Catalog=database;Persist Security Info=False;User ID=adminserver72783922;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}
Program.cs File code.
using Microsoft.Extensions.Azure;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = "Server=xxxx;Initial Catalog=database;Persist Security Info=False;User ID=adminserver72783922;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
options.SchemaName = "dbo";
options.TableName = "_Cache";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Run migration – after I’ve published my app
Enable Migration using this command on Package Manager Console enable-migrations
Then add-migration InitialCreate
Then create migrationadd-migration test-v1
update database update-database -verbose

Is connection pool shared based on connection string value?

I have ASP.NET Core Web API. The app has three functionalities that connects to DB. EF DbContext, Hangfire and Serilog Logging. All 3 reads the connection string from appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Error"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.MSSqlServer"],
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=serverip;Database=MyDb;Integrated Security=True;",
"tableName": "Logs",
"schemaName": "logging",
"autoCreateSqlTable": false
}
}
]
},
"ConnectionStrings": {
"DefaultConnection": "Server=serverip;Database=MyDb;Integrated Security=True;"
}
}
in Programs.cs I have configured Serilog that auto reads the connectionString from appsettings
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:30000")
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
if (!hostingContext.HostingEnvironment.IsLocal())
{
logging.ClearProviders();
}
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostingContext.Configuration)
.CreateLogger();
logging.AddSerilog();
});
in Startup.cs we have Hangfire and EF DbContext using the same connection value
public void ConfigureServices(IServiceCollection services)
{
//dbContext
var connection = configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<MyDBContext>(options => options.UseSqlServer(connection));
services.AddHangfire(config => config.UseSqlServerStorage(connection));
}
Serilog, has separate entry in appsettings for connection string but the value for the connection string is same.
Each funcationality has its own SQL schema. DbContext -> dbo schema, Hangfire->hangfire schema, Serilog ->logging schema
As per the documentation
A connection pool is created for each unique connection string. When a
pool is created, multiple connection objects are created and added to
the pool so that the minimum pool size requirement is satisfied.
Connections are added to the pool as needed, up to the maximum pool
size specified (100 is the default).
Since the value of the connection string is same, does that mean all these 3 funcationalities sharing the same connection pool?
UPDATE 1
The reason I asked this question because we were seeing error
System.InvalidOperationException: Timeout expired. The timeout period
elapsed prior to obtaining a connection from the pool. This may have
occurred because all pooled connections were in use and max pool size
was reached.
Here is my implementation of service. Since service is registered with Scope lifetime, the DI container should dispose service at the end of request and that should dispose the dbContext as well.
public interface IBaseService : IDisposable
{
}
public abstract class BaseService : IBaseService
{
private bool _disposed = false;
protected readonly MyDBContext _dbContext;
protected BaseService(MyDBContext dbContext)
{
_dbContext = dbContext;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
}
// Free any other managed objects here.
}
// Free any unmanaged objects here.
_disposed = true;
}
}
public interface IOrderService : IBaseService
{
Task<Order> Create(Order order);
}
public class OrderService:BaseService,IOrderService
{
public OrderService():base(MyDBContext dbContext)
{
}
public async Task<Order> Create(Order order)
{
_dbContext.Orders.Add(order);
await _dbContext.SaveChangesAsync();
// at this point I am guessing the SQL connection will be closed by the DBContext
}
}
and in Startup.cs it service is regiered with Scope lifetime
services.AddScoped<IOrderService, OrderService>();

ApplicationIntent=ReadOnly missing

I'm trying to create EF Core 3.1 context with readonly application intent for connection redirection to replica database.
When context's .ctor are called, connection string in SqlServerOptionsExtension extension of DbContextOptions has no ApplicationIntent=ReadOnly option.
Example code:
Startup.cs
protected override void DoEndConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlServer()
.AddDbContext<ReadOnlyContext>(options =>
{
options.UseSqlServer("...;ApplicationIntent=ReadOnly");
}, ServiceLifetime.Scoped);
}
ReadOnlyContext.cs
public class ReadOnlyContext : DbContext
{
protected MovedContext(DbContextOptions<MovedContext> options) : base(options)
{
}
}
I have tried to set up connection in OnConfiguring method and it worked as intended.
How i could pass readonly connection string to context upon creating it from Startup class?

How can i set language from SQLServerDataSource using Spring data

Good I have the need to make certain queries to the database sql server working with dates, I am presented with the inconvenience that as language in the installation of sql server is in English therefore the results are defined in that language for example to perform the consult with the following function DATENAME (WEEKDAY, date) the result would be for example Tuesday, as far as my need is to show it in Spanish.
A solution that I have applied is to do this from the application, obtaining the date and perform the conversion from the application.
But I would like to know if it is possible to make this configuration globally from the application through the configuration parameters of the DataSource?
Configuration:
#Configuration
#EnableJpaRepositories(basePackages = { "com.company.app.repository" })
#ComponentScan(basePackages = { "com.company.app.repository" })
#EnableTransactionManagement
#EnableJpaAuditing
#PropertySource("classpath:/db.properties")
public class ApplicationConfig {
#Autowired
private Environment environment;
//private static final Logger LOGGER = LogManager.getLogger(ApplicationConfig.class);
#Bean
public DataSource dataSource() {
// OracleDataSource oracleDS = null;
SQLServerDataSource dataSource = null;
// oracleDS = new OracleDataSource();
dataSource = new SQLServerDataSource();
dataSource.setURL(environment.getProperty("cendb.url"));//
dataSource.setUser(environment.getProperty("cendb.user"));//
dataSource.setPassword(environment.getProperty("cendb.password"));
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setShowSql(true);
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.SQLServerDialect");
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.company.app.model");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
#Bean
public AuditorAware<String> createAuditorProvider() {
return new CustomAuditorAware();
}
#Bean
public AuditingEntityListener createAuditingListener() {
return new AuditingEntityListener();
}

Spring LDAP/Active Directory with SQL

I am trying to enable both JDBA and Active Directory Authentication , i made great progress but currently i am stuck as userDetailsService is trying to compare the password in LdapUserDetails which does not exist . When checking the log i see it is able to query the user and authenticate and get the roles correctly.
I know i should use bindService or so , but i couldn't find till now how to do that.
Below is what i did .
in WebSecurityConfigurerAdapter
#Autowired
public void configureGlobal(UserDetailsService userDetailsService,UserLdapRepositoryUserDetailsService userLdapRepositoryUserDetailsService,AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService).
and()
.userDetailsService(userLdapRepositoryUserDetailsService);
}
For LDAP Configuration
#Bean
public BaseLdapPathContextSource contextSource() {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://XXXXX:389/dc=XXXXXX,dc=co");
//contextSource.setUserDn("CN=Ali Shahbour,OU=Users,DC=XXXXXXX,DC=co");
contextSource.setUserDn("XXXXXX");
contextSource.setPassword("XXXXXX");
return contextSource;
}
#Bean
#Autowired
public LdapUserSearch userSearch(BaseLdapPathContextSource contextSource) {
FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch("", "(uid={0})", contextSource);
return userSearch;
}
#Bean
#Autowired
public LdapAuthoritiesPopulator authoritiesPopulator(BaseLdapPathContextSource contextSource) {
DefaultLdapAuthoritiesPopulator authoritiesPopulator = new DefaultLdapAuthoritiesPopulator(contextSource, "OU=CDRMonitor");
authoritiesPopulator.setGroupSearchFilter("(member={0})");
//authoritiesPopulator.setRolePrefix("ROLE");
authoritiesPopulator.setSearchSubtree(true);
//authoritiesPopulator.setConvertToUpperCase(true);
return authoritiesPopulator;
}
As for the LdapUserDetailsService
#Service("userLdapRepositoryUserDetailsService")
public class UserLdapRepositoryUserDetailsService extends LdapUserDetailsService {
private final UserRepository userRepository;
#Autowired
public UserLdapRepositoryUserDetailsService(LdapUserSearch userSearch,
LdapAuthoritiesPopulator authoritiesPopulator,UserRepository userRepository) {
super(userSearch, authoritiesPopulator);
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
UserDetails userDetails = super.loadUserByUsername(username);
//User user = userRepository.findByEmail(username);
User user = new User();
return new LdapUserRepositoryUserDetails(user, userDetails);
}
#Override
public void setUserDetailsMapper(UserDetailsContextMapper userDetailsMapper) {
super.setUserDetailsMapper(userDetailsMapper);
}
private final static class LdapUserRepositoryUserDetails extends User implements LdapUserDetails {
private final LdapUserDetailsImpl ldapUserDetailsImpl;
private LdapUserRepositoryUserDetails(User user,UserDetails userDetails) {
super(user);
ldapUserDetailsImpl = (LdapUserDetailsImpl) userDetails;
}
private static final long serialVersionUID = 5639683223516504866L;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return ldapUserDetailsImpl.getAuthorities();
}
#Override
public String getUsername() {
// TODO Auto-generated method stub
return ldapUserDetailsImpl.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return ldapUserDetailsImpl.isAccountNonExpired();
}
#Override
public boolean isAccountNonLocked() {
return ldapUserDetailsImpl.isAccountNonLocked();
}
#Override
public boolean isCredentialsNonExpired() {
return ldapUserDetailsImpl.isCredentialsNonExpired();
}
#Override
public boolean isEnabled() {
return ldapUserDetailsImpl.isEnabled();
}
#Override
public String getDn() {
return ldapUserDetailsImpl.getDn();
}
}
}
LDAP and SQL in an authentication context are in general not used together,
because LDAP BIND authentication sends the password to the LDAP server instead of retrieving a hash value of the password.
The intended procedure of LDAP Authentication is as follows:
Usually a spring security UsernamePassword filter is used to pick up the credentials and is active by default. e.g. if you us a login form, when submitting the form, this filter picks up the credentials.
Next an LDAP Authentication Provider performs a login (LDAPBindAuthenticator) against the LDAP server (LDAP ContextSource) to verify the credentials.
If the login is successful, the LDAP Authentication Provider searches the LDAP for a user entry. This can be customised by providing a 'usersearch' spring bean.
If the user entry is found, the LDAP Authority mapper will map attributes of the user entry to groups/roles in spring security. By default this are all OU attributes
Lastly a new authentication object is made with the username and retrieved groups from the LDAP.
How to integrate LDAP Authentication using Spring XML is explained here.
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/ldap.html

Resources