Skip to content

Commit 2d2cf56

Browse files
committed
updated readme
1 parent 884ae64 commit 2d2cf56

File tree

1 file changed

+67
-11
lines changed

1 file changed

+67
-11
lines changed

README.md

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,17 @@ Guidance on onboarding samples to docs.microsoft.com/samples: https://review.doc
2222
Taxonomies for products and languages: https://review.docs.microsoft.com/new-hope/information-architecture/metadata/taxonomies?branch=master
2323
-->
2424

25-
TDB
25+
An API should allow its users to securely access the data in the database used by the API itself. At the same time it also must assure that data is protected and secured from those users who doesn't have enough authorization. This is even more important when creating multi-tenant applications.
26+
27+
Azure SQL offers an amazing feature to secure data at the database level, so that all the burden of taking care of such important and critical effort is done automatically by the database engine, so that the API code can be cleaner and easier to maintain and evolve. Not to mention better performances and improved efficiency as data will not leave the database at all, if the user has not the correct permissions.
28+
29+
This repo guides you to the creation of a API solution, deployable in Azure, that take advantage of Azure SQL Row Level Security to create secure API using Python, Flask and JWT. The same approach could be used with .NET or any other language that allows you to connect to Azure SQL.
30+
31+
A detailed video on how this sample work is available here:
32+
33+
https://youtu.be/Qpv8ke8ZuQ8
34+
35+
The sample simulate an authenticated user by passing in the JWT token (that you'll generate using the `pyjwt` tool) the hashed User Id. From a security point of view you want to make sure that a user can access only to his own data (or to the data s/he has been authorized to).
2636

2737
## Install Sample Database
2838

@@ -36,10 +46,6 @@ Otherwise you can restore the `rls_sample` database by using the
3646

3747
[How To Restore Database](https://github.com/yorek/azure-sql-db-samples#restore-wideworldimporters-database)
3848

39-
## Enabled Row Level Security
40-
41-
TDB
42-
4349
If you need any help in executing the SQL script, you can find a Quickstart here: [Quickstart: Use Azure Data Studio to connect and query Azure SQL database](https://docs.microsoft.com/en-us/sql/azure-data-studio/quickstart-sql-database)
4450

4551
## Run sample locally
@@ -68,14 +74,14 @@ Linux:
6874

6975
```bash
7076
export FLASK_ENV="development"
71-
export SQLAZURECONNSTR_WWIF="<your-connection-string>"
77+
export SQLAZURECONNSTR_RLS="<your-connection-string>"
7278
```
7379

7480
Windows:
7581

7682
```powershell
7783
$Env:FLASK_ENV="development"
78-
$Env:SQLAZURECONNSTR_WWIF="<your-connection-string>"
84+
$Env:SQLAZURECONNSTR_RLS="<your-connection-string>"
7985
```
8086

8187
Your connection string is something like:
@@ -98,22 +104,72 @@ Python will start the HTTP server and when everything is up and running you'll s
98104
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
99105
```
100106

101-
Using a REST Client (like [Insomnia](https://insomnia.rest/), [Postman](https://www.getpostman.com/) or curl), you can now call your API, for example:
107+
Using a REST Client (like [Insomnia](https://insomnia.rest/), [Postman](https://www.getpostman.com/) or curl), you can now call your API. The API requires a Bearer Token that contains the Hashed User Id of the user you want to simulate:
108+
109+
|User|Hashed Id|
110+
|---|---|
111+
|Jane Dean|6134311589|
112+
|John Doe|1225328053|
113+
114+
the definition of who can see what is stored in the `rls.SensitiveDataPermissions` table.
115+
116+
To generate the Bearer Token you can use the `pyjwt` that is automatically installed by the `pyjwt` python package. Use the key `mySUPERs3cr3t` to sign the JWT message.
117+
118+
Linux:
102119

103120
```bash
104121
export token=`pyjwt --key=mySUPERs3cr3t encode iss=me exp=+600 user-hash-id=1225328053`
105122
curl -s -H "Authorization: Bearer ${token}" -X GET http://localhost:5000/sensitive-data/more | jq .
106123
```
107124

125+
Windows:
126+
127+
```powershell
128+
$token = pyjwt --key=mySUPERs3cr3t encode iss=me exp=+600 user-hash-id=1225328053
129+
(Invoke-WebRequest -Uri http://localhost:5000/sensitive-data/more -Method GET -Headers @{"Authorization"="Bearer $token"}).Content
130+
```
131+
108132
and you'll get info on Customer 123:
109133

110134
```json
111-
TDB
135+
[
136+
{
137+
"Id": 1,
138+
"FirstName": "Jane",
139+
"LastName": "Dean",
140+
"EvenMore": [...]
141+
},
142+
{
143+
"Id": 2,
144+
"FirstName": "John",
145+
"LastName": "Doe",
146+
"EvenMore": [...]
147+
}
148+
]
149+
```
150+
151+
As you can see, data for both users is returned, even if you are invoking the API using a specific User. This is because the Row Level Security feature is *disabled*.
152+
153+
## Enable Row Level Security
154+
155+
To enable to Row Level Security Policy execute the following code in the sample database:
156+
157+
```sql
158+
alter security policy rls.SensitiveDataPolicy with (state = on)
112159
```
113160

114-
Check out more samples to test all implemented verbs here:
161+
If you try to access the same API again, you'll now see only the data for the user you are simulating:
115162

116-
[cUrl Samples](./sample-usage.md)
163+
```json
164+
[
165+
{
166+
"Id": 2,
167+
"FirstName": "John",
168+
"LastName": "Doe",
169+
"EvenMore": [...]
170+
}
171+
]
172+
```
117173

118174
## Debug from Visual Studio Code
119175

0 commit comments

Comments
 (0)