Security

Labels
AJAX(112) App Studio(7) Apple(1) Application Builder(245) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcode(2) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(12) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) Device(1) DotNetNuke(12) EASE(20) Email(6) Features(101) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(5) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(18) OAuth(9) OAuth Scopes(1) OAuth2(13) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(11) PKCE(2) Postgre SQL(1) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(183) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(81) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(338) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
Security
Friday, May 4, 2012PrintSubscribe
Rapidly Find Data Using Quick Find

The simplest method to search for data in Code On Time web applications is Quick Find.

Quick Find is located on the left side of the action bar above grid views. It allows searching for values in the visible fields. The application will split the search text by spaces and use each word as a filtering parameter when executing a query.

Quick Find text box on the action bar of Code On Time web application

For example, let’s find any customer that contains the text “owner”. Enter the text in the Quick Find, and press Enter on your keyboard. You can see that we now have a list of records that contain “owner” in the Contact Title field.

Search results for 'owner' in Customers grid view

Let’s find all owners in Mexico. In the Quick Find box, type “owner mexico”, and press Enter on your keyboard. This will fetch a shorter list. All data rows will contain both words in the fields. For example, “owner” is found in Contact Title, and “mexico” is found in Country.

The screenshot shows the search result for 'owner mexico'.

The order of words in the query does not matter. For example, search for “france owner”. The search will find all three owners from France.

Search results for 'France owner' in Customers grid view

You can also search for numeric values in any field of the record. Switch to the Products page, and search for “40”. The first product has “40” in Units On Order. The second product has a Unit Price of “40”. The third product has “40” in Quantity Per Unit.

Search results for '40' in Products grid view

Numbers and words can be mixed in the search query. Search for “40 biscuit”. The search query found two records that have those parameters.

Search results for '40 biscuit' in Products grid view

The user input is never incorporated in the SQL text, eliminating possibility of an SQL Injection attack. Search for “drop database”. No records will be found, and the database will not be dropped. The application framework will include parameter names in the query and pass the user-entered criteria as parameter values.

SQL injection attack by searching for 'drop database' is ineffective

You can clear any filter by either clicking on the “x” icon on the right side of the filter detail bar, or by clicking on the filter description.

Clear filter by clicking on the text of the filter description in Code On Time web app

Developers can also configure “hidden” fields to participate in the Quick Find.

Friday, April 13, 2012PrintSubscribe
Permalinks Feature

Often, multiple users may need to provide a link or bookmark to a specific record. Code On Time applications offer the ability to create permanent links for a record.

First, you need to select a record.

Selected employee record in Code On Time web application

In the top left corner of the page, click on the Permalink option.

Permalink option on membership bar of a Code On Time web application

A textbox will appear to the right side of the link, containing the URL (permanent link) for the record. If you mouse over the permalink, you will see information about the record matching the info provided in the Summary area on the left side of the page. You can copy this link to the clipboard and share it with anyone via email or an instant messaging service.

Permalink created for selected record in Code On Time web application

The icon immediately to the right of the textbox allows you to add the link to your Bookmarks.

Add Permalink to Favorites

You can close the permalink textbox by either clicking on Permalink again or selecting the the far right Close icon.

Closing the Permalink textbox in Code On Time web application

If you access the permalink via bookmark or click on one received from another application user, you will see the following prompt to log in to the web application.

Log in prompt in Code On Time web app

The application will automatically redirect you to the correct page and select the record, provided that you have permission to access the application and see the data.

Permalinked record displayed after log in to web application

You can enable Permalinks in the Project Wizard.

Friday, March 9, 2012PrintSubscribe
Using ConnectionStringSettingsFactory in “Database per Tenant” Apps

Multi-tenant web applications can be constructed using one of the two methods:

  • Tenants co-exist in the same database. Data is segregated based on the user identity.
  • Each tenant has a private database.

Code On Time web applications offer excellent support for multi-tenant data segregation.

Let’s discuss how to implement a multi-tenant application with private databases.

Internet users arrive to your web application protected with ASP.NET Membership. If the user is not authenticated then there is no way to know, which private database is the final destination for this user. Therefore you either need to implement a single database of user accounts (for example an ASP.NET Membership database) or rely on the elements of the user name (for example the domain portion of the email address) to authenticate the user.

The second solution is more complex when it comes to implementing the user authentication. We will consider the first scenario and assume that the main database of the application has ASP.NET Membership installed already. Follow instructions at http://codeontime.com/learn/sample-applications/northwind to create an application with the membership feature.

The main application database will have the application tables and views. We will call it a “master” database. You will develop your application using the master database. Create additional databases with the same schema but do not include the membership infrastructure in them.

Private Database Derived From DNS Records

Deploy your application. Create CNAME records in the DNS configuration of your Internet domain for each client that must have a private database. Point the CNAME record of each client to the name of your web application. Instruct your clients to sign in the application using their dedicated domain name defined in the CNAME record.

For example, if your main application name is myapp.contoso.com then a client with a dedicate database can access your application as clientname.contoso.com. Also make sure that the name of the master database is myapp.constoso.com and the private database names for the clients use the format clientname.contoso.com.

Unauthenticated users will be authenticated against the master database membership. If you do nothing else then the authenticated users will see the contents of the master database while navigating through the application pages.

Implement the following class in your application to redirect authenticated users to the private database.

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Data.SqlClient;
namespace MyCompany.Data
{
    public partial class ConnectionStringSettingsFactory
    {
        protected override ConnectionStringSettings CreateSettings(string connectionStringName)
        {
            ConnectionStringSettings settings = base.CreateSettings(connectionStringName);
            // if the user is not authenticated then use the default database
            if (HttpContext.Current.User.Identity.IsAuthenticated &&
                HttpContext.Current.Request.Url.Host.Contains("contoso.com"))
            {
                SqlConnectionStringBuilder csb = 
                    new SqlConnectionStringBuilder(settings.ConnectionString);
                csb.InitialCatalog = HttpContext.Current.Request.Url.Host;
                settings = new ConnectionStringSettings(null, csb.ToString(), 
settings.ProviderName); } return settings; } } }

Visual Basic:

Imports Microsoft.VisualBasic
Imports MyCompany.Data
Imports System.Data.SqlClient

Namespace MyCompany.Data
    Partial Public Class ConnectionStringSettingsFactory
        Protected Overrides Function CreateSettings(
            connectionStringName As String) As System.Configuration.ConnectionStringSettings
            Dim settings As ConnectionStringSettings = 
MyBase.CreateSettings(connectionStringName) If (HttpContext.Current.User.Identity.IsAuthenticated AndAlso HttpContext.Current.Request.Url.Host.Contains(".contoso.com")) Then Dim csb As SqlConnectionStringBuilder = New SqlConnectionStringBuilder(settings.ConnectionString) csb.InitialCatalog = HttpContext.Current.Request.Url.Host settings = New ConnectionStringSettings(Nothing, csb.ToString(),
settings.ProviderName) End If Return settings End Function End Class End Namespace

This code inspects the name of the host specified in the URL of the current request. If the authenticated user is trying to access the production deployment and “*.contoso.com” is detected in the host name then the code will create a database-specific connection string and change the database name to the name of the host.

Our example uses Microsoft SQL Server database. That is why we are creating SqlConnectionStringBuilder class instance. Use the class that matches your back-end database. The name of the SQL Server database is specified in InitialiCatalog property. Implementations of connection string builder for other database engines may use a different property for the same purpose.

If your clients do have a web presence then you can instruct them to create their private CNAME Records that point to your application. Make sure to use the client’s CNAME Record as the name of the private database instance. Your clients will be able to access your web application as myapp.clientdomain.com where “clientdomain” is the client’s own domain name.

Private Database Derived From User identity

You can also implement a table in the master database that will associate the user accounts with the private databases available in the app. This table will effectively play the role of the DNS for your own application. Users will access the application via the same URL.

create table UserDatabases
(
    UserName varchar(50),
    DatabaseName varchar(50),
    primary key (UserName, DatabaseName)
)

The following code will lookup the UserDatabases table for authenticated users and adjust the connection string accordingly.

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Data.SqlClient;
namespace MyCompany.Data
{
    public partial class ConnectionStringSettingsFactory
    {
        protected override ConnectionStringSettings CreateSettings(string connectionStringName)
        {
            ConnectionStringSettings settings = base.CreateSettings(connectionStringName);
            // if the user is not authenticated then use the default database
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                SqlConnectionStringBuilder csb =
                    new SqlConnectionStringBuilder(settings.ConnectionString);
                using (SqlConnection connection = new SqlConnection(settings.ConnectionString))
                {
                    connection.Open();
                    SqlCommand command = connection.CreateCommand();
                    command.CommandText =
                        "select DatabaseName from UserDatabases where UserName=@UserName";
                    SqlParameter p = command.CreateParameter();
                    command.Parameters.Add(p);
                    p.ParameterName = "@UserName";
                    p.Value = HttpContext.Current.User.Identity.Name;
                    csb.InitialCatalog = Convert.ToString(command.ExecuteScalar());
                }
                csb.InitialCatalog = HttpContext.Current.Request.Url.Host;
                settings = new ConnectionStringSettings(null, csb.ToString(), 
settings.ProviderName); } return settings; } } }

Visual Basic:

Imports Microsoft.VisualBasic
Imports MyCompany.Data
Imports System.Data.SqlClient

Namespace MyCompany.Data
    Partial Public Class ConnectionStringSettingsFactory
        Protected Overrides Function CreateSettings(
            connectionStringName As String) As System.Configuration.ConnectionStringSettings
            Dim settings As ConnectionStringSettings =
                MyBase.CreateSettings(connectionStringName)
            If (HttpContext.Current.User.Identity.IsAuthenticated) Then
                Dim csb As SqlConnectionStringBuilder =
                    New SqlConnectionStringBuilder(settings.ConnectionString)
                Using connection As SqlConnection =
                        New SqlConnection(settings.ConnectionString)
                    connection.Open()
                    Dim command As SqlCommand = connection.CreateCommand()
                    command.CommandText =
                        "select DatabaseName from UserDatabases where UserName=@UserName"
                    Dim p As SqlParameter = command.CreateParameter()
                    p.ParameterName = "@UserName"
                    p.Value = HttpContext.Current.User.Identity.Name
                    csb.InitialCatalog = Convert.ToString(command.ExecuteNonQuery())
                End Using
                csb.InitialCatalog = HttpContext.Current.Request.Url.Host
                settings = New ConnectionStringSettings(Nothing, csb.ToString(),
                    settings.ProviderName)
            End If
            Return settings
        End Function
    End Class
End Namespace

Notice that we are using the native ADO.NET classes that are specific to SQL Server: SqlConnection and SqlCommand. Code On Time web applications can take advantage of SqlText class that wraps the ADO.NET components in a compact database-independent implementation. The class is the component of the framework of the generated web application and takes advantage of ConnectionStringSettingsFactory. We have to use the native ADO.NET classes to prevent the re-entrance in the ConnectionStringSettingsFactory. Adjust the sample with the native ADO.NET classes that match your database backend if you are not programming with Microsoft SQL Server.