diff --git a/samples/features/security/contoso-clinic/README.md b/samples/features/security/contoso-clinic/README.md index 7c6b67c9..7638a7f1 100644 --- a/samples/features/security/contoso-clinic/README.md +++ b/samples/features/security/contoso-clinic/README.md @@ -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 diff --git a/samples/features/security/permissions-posters/Permissions_Poster_SQL_Server_2017_and_SQLDB.pdf b/samples/features/security/permissions-posters/Permissions_Poster_SQL_Server_2017_and_SQLDB.pdf new file mode 100644 index 00000000..70139894 Binary files /dev/null and b/samples/features/security/permissions-posters/Permissions_Poster_SQL_Server_2017_and_SQLDB.pdf differ diff --git a/samples/features/security/permissions-posters/Permissions_Poster_SQL_Server_vNext_and_SQLDB.pdf b/samples/features/security/permissions-posters/Permissions_Poster_SQL_Server_vNext_and_SQLDB.pdf deleted file mode 100644 index e6d03495..00000000 Binary files a/samples/features/security/permissions-posters/Permissions_Poster_SQL_Server_vNext_and_SQLDB.pdf and /dev/null differ diff --git a/samples/features/security/whitepapers/microsoft-sql-and-the-gdpr.pdf b/samples/features/security/whitepapers/microsoft-sql-and-the-gdpr.pdf new file mode 100644 index 00000000..52c9a251 Binary files /dev/null and b/samples/features/security/whitepapers/microsoft-sql-and-the-gdpr.pdf differ diff --git a/samples/features/sqlvdi-linux/vdipipesample.cpp b/samples/features/sqlvdi-linux/vdipipesample.cpp index c1e85fe3..efbe5fcc 100644 --- a/samples/features/sqlvdi-linux/vdipipesample.cpp +++ b/samples/features/sqlvdi-linux/vdipipesample.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #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. diff --git a/samples/tutorials/go/README.md b/samples/tutorials/go/README.md new file mode 100644 index 00000000..13b186f5 --- /dev/null +++ b/samples/tutorials/go/README.md @@ -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 .go` diff --git a/samples/tutorials/go/columnstore.go b/samples/tutorials/go/columnstore.go new file mode 100644 index 00000000..a9994798 --- /dev/null +++ b/samples/tutorials/go/columnstore.go @@ -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) +} \ No newline at end of file diff --git a/samples/tutorials/go/connect.go b/samples/tutorials/go/connect.go new file mode 100644 index 00000000..da320b1a --- /dev/null +++ b/samples/tutorials/go/connect.go @@ -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) +} \ No newline at end of file diff --git a/samples/tutorials/go/crud.go b/samples/tutorials/go/crud.go new file mode 100644 index 00000000..efb18c9c --- /dev/null +++ b/samples/tutorials/go/crud.go @@ -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) +} \ No newline at end of file diff --git a/samples/tutorials/go/orm.go b/samples/tutorials/go/orm.go new file mode 100644 index 00000000..c68b8ae4 --- /dev/null +++ b/samples/tutorials/go/orm.go @@ -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) +} \ No newline at end of file