Merge remote-tracking branch 'refs/remotes/Microsoft/master'

This commit is contained in:
Jovan Popovic
2017-06-29 09:21:23 +02:00
10 changed files with 299 additions and 15 deletions
@@ -1,33 +1,33 @@
#Contoso Clinic Demo Application
# Contoso Clinic Demo Application
Sample application with database that showcases security features of SQL Server 2016.
## About this sample
- **Applies to:** SQL Database 2016
- **Applies to:** SQL Server 2016
- **Programming Language:** .NET C#, T-SQL
- **Authors:** Jakub Szymaszek [jaszymas-MSFT]
This project has adopted the [Microsoft Open Source Code of Conduct](http://microsoft.github.io/codeofconduct). For more information see the [Code of Conduct FAQ](http://microsoft.github.io/codeofconduct/faq.md) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
##Contents
1. [Prerequisites] (#prerequisites)
2. [Setup] (#setup)
## Contents
1. [Prerequisites](#prerequisites)
2. [Setup](#setup)
* Set up the Demo Database
* Modify the Sample Application
4. [SQL 2016 Security Features in this demo] (#sql-2016-security-features-in-this-demo)
4. [SQL 2016 Security Features in this demo](#sql-2016-security-features-in-this-demo)
* Always Encrypted
* Row Level Security
* Dynamic Data Masking
5. [Application Notes] (#application-notes)
5. [Application Notes](#application-notes)
##Prerequisites
## Prerequisites
1. Visual Studio 2015 (or newer)
2. [SQL Server 2016](https://www.microsoft.com/en-us/evalcenter/evaluate-sql-server-2016)
3. [SQL Server Management Studio](https://msdn.microsoft.com/en-us/library/mt238290.aspx)
##Setup
## Setup
### Set up the Demo Database
1. Clone/Download the repository
2. Import the *Clinic* database
@@ -75,7 +75,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct](http://micr
## SQL 2016 Security Features in this Demo
### Always Encrypted
####Enable Always Encrypted
#### Enable Always Encrypted
+ Connect to your database using SSMS:
- For more information on using SSMS to connect to a Database, [click here](https://azure.microsoft.com/en-us/documentation/articles/sql-database-connect-query-ssms/)
+ Encrypt Sensitive Data Columns using the Column Encryption Wizard
@@ -114,16 +114,16 @@ This project has adopted the [Microsoft Open Source Code of Conduct](http://micr
- Run the ContosoClinic application from Visual Studio (by hitting *F5* OR select *Debug* > *Start Debugging*)
- Click on the *Patients* tab. You should see a list of patients again.
####How did that work?
#### How did that work?
##### Connection String
Our connection string for our application now contains `Column Encryption Setting=Enabled` which instructs the driver to automatically encrypt parameters targeting encrypted columns and decrypt any results retrieved from encrypted columns, without code changes. Don't forget this for your app if you intend to use Always Encrypted functonality. For more information this feature, [see our blog](https://blogs.msdn.microsoft.com/sqlsecurity/2016/07/11/always-encrypted-in-azure-sql-database-is-generally-available/).
### Row Level Security (RLS)
####Login to the application
#### Login to the application
Sign in using (Rachel@contoso.com/Password1!) or (alice@contoso.com/Password1!)
####Enable Row Level Security (RLS)
#### Enable Row Level Security (RLS)
+ Connect to your database using SSMS:
[Instructions](https://azure.microsoft.com/en-us/documentation/articles/sql-database-connect-query-ssms/)
+ Open Enable-RLS.sql ( [Find it here](tsql-scripts/Enable-RLS.sql))
@@ -132,7 +132,7 @@ Sign in using (Rachel@contoso.com/Password1!) or (alice@contoso.com/Password1!)
#### How did that work?
#####The application leverages an Entity Framework feature called **interceptors**
##### The application leverages an Entity Framework feature called **interceptors**
Specifically, we used a `DbConnectionInterceptor`. The `Opened()` function is called whenever Entity Framework opens a connection and we set SESSION_CONTEXT with the current application `UserId` there.
##### Predicate functions
@@ -45,6 +45,8 @@
#include <string>
#include <unistd.h>
#include <uuid/uuid.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "vdi.h" // interface declaration
#include "vdierror.h" // error constants
@@ -131,7 +133,8 @@ int main(int argc, char* argv[])
"Demonstrate a Backup or Restore using the Virtual Device Interface\n");
return 1;
}
umask(0);
vds = new ClientVirtualDeviceSet();
// Setup the VDI configuration we want to use.
+5
View File
@@ -0,0 +1,5 @@
# Set up instructions
1. `go get github.com/denisenkom/go-mssqldb`
1. `go install github.com/denisenkom/go-mssqldb`
1. `go run <your_sample>.go`
+46
View File
@@ -0,0 +1,46 @@
package main
import _ "github.com/denisenkom/go-mssqldb"
import "database/sql"
import "log"
import "fmt"
import "time"
var server = "localhost"
var port = 1433
var user = "sa"
var password = "your_password"
var database = "SampleDB"
// Delete an employee from database
func ExecuteAggregateStatement(db *sql.DB) {
result, err := db.Prepare("SELECT SUM(Price) as sum FROM Table_with_5M_rows")
if err != nil {
fmt.Println("Error preparing query: " + err.Error())
}
row := result.QueryRow()
var sum string
err = row.Scan(&sum)
fmt.Printf("Sum: %s\n", sum)
}
func main() {
// Connect to database
connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;",
server, user, password, port, database)
conn, err := sql.Open("mssql", connString)
if err != nil {
log.Fatal("Open connection failed:", err.Error())
}
fmt.Printf("Connected!\n")
defer conn.Close()
t1 := time.Now()
fmt.Printf("Start time: %s\n", t1)
ExecuteAggregateStatement(conn)
t2 := time.Since(t1)
fmt.Printf("The query took: %s\n", t2)
}
+33
View File
@@ -0,0 +1,33 @@
package main
import _ "github.com/denisenkom/go-mssqldb"
import "database/sql"
import "log"
import "fmt"
var server = "localhost"
var port = 1433
var user = "sa"
var password = "your_password"
func main() {
connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d",
server, user, password, port)
conn, err := sql.Open("mssql", connString)
if err != nil {
log.Fatal("Open connection failed:", err.Error())
}
fmt.Printf("Connected!\n")
defer conn.Close()
stmt, err := conn.Prepare("select @@version")
row := stmt.QueryRow()
var result string
err = row.Scan(&result)
if err != nil {
log.Fatal("Scan failed:", err.Error())
}
fmt.Printf("%s\n", result)
}
+99
View File
@@ -0,0 +1,99 @@
package main
import _ "github.com/denisenkom/go-mssqldb"
import "database/sql"
import "log"
import "fmt"
var server = "localhost"
var port = 1433
var user = "sa"
var password = "your_password"
var database = "SampleDB"
// Create an employee
func CreateEmployee(db *sql.DB, name string, location string) (int64, error) {
tsql := fmt.Sprintf("INSERT INTO TestSchema.Employees (Name, Location) VALUES ('%s','%s');",
name, location)
result, err := db.Exec(tsql)
if err != nil {
fmt.Println("Error inserting new row: " + err.Error())
return -1, err
}
return result.LastInsertId()
}
// Read all employees
func ReadEmployees(db *sql.DB) (int, error) {
tsql := fmt.Sprintf("SELECT Id, Name, Location FROM TestSchema.Employees;")
rows, err := db.Query(tsql)
if err != nil {
fmt.Println("Error reading rows: " + err.Error())
return -1, err
}
defer rows.Close()
var count int = 0
for rows.Next(){
var name, location string
var id int
err := rows.Scan(&id, &name, &location)
if err != nil {
fmt.Println("Error reading rows: " + err.Error())
return -1, err
}
fmt.Printf("ID: %d, Name: %s, Location: %s\n", id, name, location)
count++
}
return count, nil
}
// Update an employee's information
func UpdateEmployee(db *sql.DB, name string, location string) (int64, error) {
tsql := fmt.Sprintf("UPDATE TestSchema.Employees SET Location = '%s' WHERE Name= '%s'",
location, name)
result, err := db.Exec(tsql)
if err != nil {
fmt.Println("Error updating row: " + err.Error())
return -1, err
}
return result.LastInsertId()
}
// Delete an employee from database
func DeleteEmployee(db *sql.DB, name string) (int64, error) {
tsql := fmt.Sprintf("DELETE FROM TestSchema.Employees WHERE Name='%s';", name)
result, err := db.Exec(tsql)
if err != nil {
fmt.Println("Error deleting row: " + err.Error())
return -1, err
}
return result.RowsAffected()
}
func main() {
// Connect to database
connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;",
server, user, password, port, database)
conn, err := sql.Open("mssql", connString)
if err != nil {
log.Fatal("Open connection failed:", err.Error())
}
fmt.Printf("Connected!\n")
defer conn.Close()
// Create employee
createId, err := CreateEmployee(conn, "Jake", "United States")
fmt.Printf("Inserted ID: %d successfully.\n", createId)
// Read employees
count, err := ReadEmployees(conn)
fmt.Printf("Read %d rows successfully.\n", count)
// Update from database
updateId, err := UpdateEmployee(conn, "Jake", "Poland")
fmt.Printf("Updated row with ID: %d successfully.\n", updateId)
// Delete from database
rows, err := DeleteEmployee(conn, "Jake")
fmt.Printf("Deleted %d rows successfully.\n", rows)
}
+98
View File
@@ -0,0 +1,98 @@
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mssql"
)
var server = "localhost"
var port = 1433
var user = "sa"
var password = "your_password"
var database = "SampleDB"
type User struct {
gorm.Model
FirstName string
LastName string
}
type Task struct {
gorm.Model
Title string
DueDate string
IsComplete bool
UserID uint
}
func ReadAllTasks(db *gorm.DB){
var users []User
var tasks []Task
db.Find(&users)
for _, user := range users{
db.Model(&user).Related(&tasks)
fmt.Printf("%s %s's tasks:\n", user.FirstName, user.LastName)
for _, task := range tasks {
fmt.Printf("Title: %s\nDueDate: %s\nIsComplete:%t\n\n",
task.Title, task.DueDate, task.IsComplete)
}
}
}
func UpdateSomeonesTask(db *gorm.DB, userId int){
var task Task
db.Where("user_id = ?", userId).First(&task).Update("Title", "Buy donuts for Luis")
fmt.Printf("Title: %s\nDueDate: %s\nIsComplete:%t\n\n",
task.Title, task.DueDate, task.IsComplete)
}
func DeleteSomeonesTasks(db *gorm.DB, userId int){
db.Where("user_id = ?", userId).Delete(&Task{})
fmt.Printf("Deleted all tasks for user %d", userId)
}
func main() {
connectionString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s",
server, user, password, port, database)
db, err := gorm.Open("mssql", connectionString)
if err != nil {
panic("failed to connect database")
}
gorm.DefaultCallback.Create().Remove("mssql:set_identity_insert")
defer db.Close()
fmt.Println("Migrating models...")
db.AutoMigrate(&User{})
db.AutoMigrate(&Task{})
// Create awesome Users
fmt.Println("Creating awesome users...")
db.Create(&User{FirstName: "Andrea", LastName: "Lam"}) //UserID: 1
db.Create(&User{FirstName: "Meet", LastName: "Bhagdev"}) //UserID: 2
db.Create(&User{FirstName: "Luis", LastName: "Bosquez"}) //UserID: 3
// Create appropriate Tasks for each user
fmt.Println("Creating new appropriate tasks...")
db.Create(&Task{
Title: "Do laundry", DueDate: "2017-03-30", IsComplete: false, UserID: 1})
db.Create(&Task{
Title: "Mow the lawn", DueDate: "2017-03-30", IsComplete: false, UserID: 2})
db.Create(&Task{
Title: "Do more laundry", DueDate: "2017-03-30", IsComplete: false, UserID: 3})
db.Create(&Task{
Title: "Watch TV", DueDate: "2017-03-30", IsComplete: false, UserID: 3})
// Read
fmt.Println("Reading all the tasks...")
ReadAllTasks(db)
// Update - update Task title to something more appropriate
fmt.Println("Updating Andrea's task...")
UpdateSomeonesTask(db, 1)
// Delete - delete Luis's task
DeleteSomeonesTasks(db, 3)
}