Entity Framework connection to SQL Azure DB using access token - entity-framework

We have web application which connects to SQL Azure DB. I have configured my application with Application ID and certificate. We would like to make use of Access Token Approach for connecting to SQL Server, As per below link, connecting through token approach to SQL Server is not a reliable approach. Any recommended way of connecting instead of User ID and Password.
Connect to Azure SQL using Azure Active Directory from an Azure Website?
Can anyone let me know if they have implemented SQL Azure DB AAD token based authentication using entity framework and is it right way for connecting.

According to your description, I followed the tutorial about using AAD Authentication for Azure SQL Database.
As this tutorial mentioned about Azure AD token authentication:
This authentication method allows middle-tier services to connect to Azure SQL Database or Azure SQL Data Warehouse by obtaining a token from Azure Active Directory (AAD). It enables sophisticated scenarios including certificate-based authentication.You must complete four basic steps to use Azure AD token authentication:
Register your application with Azure Active Directory and get the client id for your code.
Create a database user representing the application. (Completed earlier in step 6.)
Create a certificate on the client computer runs the application.
Add the certificate as a key for your application.
Then I followed the code sample in this blog for getting started with this feature, and it works as expected.
Can anyone let me know if they have implemented SQL Azure DB AAD token based authentication using entity framework and is it right way for connecting.
Based on the above code sample, I added EntityFramework 6.1.3 for implementing SQL Azure DB AAD token based authentication using entity framework. After some trials, I could make it work as expected. Here are some details, you could refer to them.
DbContext
public class BruceDbContext : DbContext
{
public BruceDbContext()
: base("name=defaultConnectionString")
{ }
public BruceDbContext(SqlConnection con) : base(con, true)
{
Database.SetInitializer<BruceDbContext>(null);
}
public virtual DbSet<User> Users { get; set; }
}
DataModel
[Table("Users")]
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[StringLength(50)]
public string UserName { get; set; }
public DateTime CreateTime { get; set; }
}
Program.cs
class Program
{
static void Main()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder["Data Source"] = "brucesqlserver.database.windows.net";
builder["Initial Catalog"] = "brucedb";
builder["Connect Timeout"] = 30;
string accessToken = TokenFactory.GetAccessToken();
if (accessToken == null)
{
Console.WriteLine("Fail to acuire the token to the database.");
}
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
try
{
connection.AccessToken = accessToken;
//working with EF
using (var model = new BruceDbContext(connection))
{
var users= model.Users.ToList();
Console.WriteLine($"Results:{Environment.NewLine}{JsonConvert.SerializeObject(users)}");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.WriteLine("Please press any key to stop");
Console.ReadKey();
}
}
Result
Note: The contained database user for your application principal via CREATE USER [mytokentest] FROM EXTERNAL PROVIDER does not has any permissions to access your database. You need to grant privileges for this user, for more details you could refer to this issue.
Additionally, when you construct the DbContextinstance, you need to implement the SqlConnection instance with a valid AccessToken. AFAIK, you need to handle the token refreshing when the token is expired.

Related

How to create my own table using EF in asp net core identity

Currently, I have EF working perfectly fine with asp net core identity. My web app allows users to login in 2 ways: using their local account and using their azure active directory account. However, only the allowed azure directory accounts are allowed to log in. Therefore, I need to create another table to hold those accounts to cross check when they log in.
If you want to create a new table for the Identity project, I suggest you could try to modify the identity EF's dbcontext with the new create model class.
More details, you could refer to below codes:
public class UserRelationship
{
public int UserId { get; set; }
}
Modify the ApplicationDbContext :
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<UserRelationship> UserRelationships { get; set; }
}
Then you could enable the migration and update the database like this article shows.

Using DTO or request.param in Express/TypeORM Rest Api

Im creating a REST API with express/TypeORM in Typescript.
My application stores users in mysql database, and users can create boards in the application.
When a user create a board i have to send the userId from the client to the backend to identify which user created this table.
1: I created a DTO:
POST:
v1/boards
import { Board } from "../entity/Board";
class BoardDTO {
public board!: Board;
public userId!: string;
};
export default BoardDTO;
to get the userId from the request.body.
OR
I can send the userId in the request url as a parameter like this:
POST:
v1/:userId/boards
The question is which one is the better pattern in real life???
get userId from body or from the request.param????

Error while fetching page of documents in Azure CosmosDB Portal

So I'm using Microsoft's Microsoft.Azure.DocumentDB.Core api to connect to my Cosmos DB from my .Net Core app.
Everything is working fine in that I can create, edit, and get documents, as well as create a new database or collection. If I create a database or collection using the DocumentDB.Core api, I can see them in my azure portal. However, when I create documents, I can not see them. Whenever I try to load my documents, I get this error a number of times equal to the number of documents I have.
Error while fetching page of documents {"code":400,"body":"Command find failed: Unknown server error occurred when processing this request.."}
I know I have existing records tho because if I save the Id I get back on creation, I can then look it up using the DocumentDB.Core api.
Here is my model that I am passing:
public class Api
{
public Api()
{
Client = new ExpandoObject();
}
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
public ExpandoObject Client { get; set; }
}
NOW, before I switched to DocumentDB.Core, I was using MongoDB.Driver, and this was my model:
public class Api
{
public Api()
{
Client = new ExpandoObject();
}
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("client")]
public ExpandoObject Client { get; set; }
}
Using MongoDB.Driver, and the above model, I was able to see my data in the azure portal.
Is there a reason why I cannot see data in the Azure CosmosDB portal using Microsoft's own tool for it? Am I missing a property? The only thing I notice that is different is that using MongoDB.Drive, my id was _id in my created document, and using DocumentDB.Core my id is id in my created document. I'm not sure if that matters though, or how to address it.
Here is simillar issue you can take a look:
Importing Json using DocumentDB Data Migration tool gives "Error while fetching page of documents code: 400" in CosmosDB
Further to understand,Below could be the reason for error code 400:-
-The JSON, SQL, or JavaScript in the request body is invalid.
-In addition, a 400 can also be returned when the required properties of a resource are not present or set in the body of the POST or PUT on the resource.
-400 is also returned when the consistent level for a GET operation is overridden by a stronger consistency from the one set for the account.
-400 is also returned when a request that requires an x-ms-documentdb-partitionkey does not include it.
Hope it helps.

Delete column in a table azure mobile app

Table already had Delete column for soft delete from web application.
Same table I have pointed to azure mobile services/app.
Also created DeleteMS column for mobile services and used auto mapper in WebApiConfig.cs.
While creating DTO, I rename old Delete column to IsDelete and kept as it is EntityData-Delete property.
Contactdto
public class Contactdto : EntityData
{
public int contact_id { get; set; }
public bool IsDeleted { get; set; }
//public bool DeletedMS { get; set; } //manually added column
}
WebApiConfig.cs
cfg.CreateMap<tblcontact, Contactdto>()
.ForMember(dto => dto.IsDeleted, map => map.MapFrom(tbl => tbl.deleted));
cfg.CreateMap<Contactdto, tblcontact>()
.ForMember(tbl => tbl.DeletedMS, map => map.MapFrom(dto => dto.Deleted));
Is this a right approach? or shall I use same column already we had?
Once record is deleted from mobile app. Will it affect in Web Application after sync service run?
Please help.
If you already implemented soft delete in your web app, it's easiest to just use that exact same column in your Mobile App backend. The only way a record will be marked as deleted is when there is a DELETE call, either through the /tables endpoint or the mobile client.
Also, make sure you are using Mobile Apps, as that is the latest version of the service. See What are Mobile Apps.

Resource level authorization in RESTful service

Let /users/{id} be a resource url in RESTful service.
Basic authentication is enabled and only authenticated users are allowed to access the url.
Example Scenario:
User_1 & User_2 are authenticated users with userId 1 & 2.
Since both are authenticated, both of them are having access to,
/users/1
/users/2
But the expectation is User_1 should have access to /users/1 and not to /users/2 or other userId.
Question:
How to do resource level authorization in RESTful services?
Note: I am implementing RESTful using Jax-RS (with Apache CXF implementation), helpful if you could explain with Jax-RS.
-Barath
Edit:
As Donal mentioned, I am not looking for role based authorization rather resource level authorization.
To give an example, lets say /users/{id}/photos/{photoId} be another resource url. User_1 should be given access to the photos belong to him only. If photoId of 2 belonging to user_2, then we should give http_404 error code for user_1 when a request /users/1/photos/2 is requested.[Since User_1 is also authenticated user he can invoke /users/2/photos/2, so we must identify the user id based on authentication parameters than via resource url]
Only solution I can think of is, include the unique id which determines the authorization in each query like,
Instead of SELECT * FROM PHOTO_TBL WHERE PHOTO_ID=2;
use SELECT * FROM PHOTO_TBL, USER_TBL WHERE PHOTO_ID=2 AND USER_ID=1 AND USER_ID=PHOTO_ID;
with this resources are delivering data that belongs to specific user. [There should be a mechanism to prevent the modification of the unique id in client side which is used to decide on authorization(userId in this case), since all requests are STATELESS request]
Caveat: Each and every query should be intelligent enough to understand the security concerns and include extra join. This is a bad design to tie up security logic to every business function.
I am yet to look into Spring security and how it can be used in this use case.
I would recommend not having the user id in the url (as if it's being 'limited' by a Basic Auth header then you may as well just have it 'specified' by the Basic auth header). This will reduce the risk of introducing a Direct Object Reference Vulnerability - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References)
In this case you could have one of the following urls:
/users/CURRENT
/me
As photos is a sub resource then you could just create the photos with a "sequence number" within the user. In a sql database this would mean having a "compound key" across both user and photo columns.
/users/CURRENT/photo/{user_photo_seq}
/me/photo/{user_photo_seq}
Your SQL would then look something like:
SELECT * FROM PHOTO_TBL WHERE USER_ID=<BasicAuthUsername> AND PHOTO_ID=<path param value>;
A good explanation of "Basic Auth Headers":
http://en.wikipedia.org/wiki/Basic_access_authentication
JAX-RS specifies sub-resource where instead of handling request in a method, processing is delegated to other object - sub-resource.
Using sub-resources it's enought to take care of the root resource and nested ones will be secured as well.
In the example you can see UserResource and all it's sub-resources available only to authorized user.
#Path("/user/{userId}")
public class UserResource {
private final String userId;
public UserResource(#PathParam("userId") String userId, #Context SecurityContext securityContext) {
this.userId = userId;
boolean authorized = /* authorization code */;
if (!authorized) { throw new WebApplicationException(Status.UNAUTHORIZED); }
}
#Path("photo")
public PhotoResource getPhotoResource() {
return new PhotoResource(userId);
}
}
public class PhotoResource {
private final String userId;
public PhotoResource(String userId) {
this.userId = userId;
}
#GET
public Response listAll() { /* ... */ }
#GET
#Path("{photoId}")
public Response present() { /* ... */ }
}