different logins access different data from tables - sql-server-2008

I am using MVC 3, and mssql 2008 r2 and,
I was wondering if there is an automated mechanism that associates different logins to different data from database tables.
For example I want to create a calendar. But I want each user to view only his own entries. So I have a table Appointment with time and place. But I do not want to include an association from LDAP because I will need to do that in a number of places.
Adam

If you are not planning to do this in the application logic, then the only way I can currently think of to do this is through the use of stored procedures or table valued functions.
What you would do is create what are often referred to as CRUD (Create Read Update Delete) stored procedures for the tables. Obviously if you are only reading from the table(s), then only a read sproc is needed.
Within the stored procedure, you can put in logic to filter the results based on the user's login.
You can assign the user to a role in the database and give that role execute privilege on the stored procedure. Or if you are using a table value function, you would give the role SELECT privilege on the function. You would not give the user any privileges to view the table itself.
Ex.
CREATE ROLE CalendarReader AUTHORIZATION dbo;
GO
CREATE PROCEDURE Calendar_Get
AS
SET NOCOUNT ON;
SELECT
EventDate
,EventText
FROM
Calendar
WHERE
UserLogin = suser_sname()
;
GO
GRANT EXECUTE ON Calendar_Get TO CalendarReader;
GO

There is nothing else for it but to have your database be structured in such a way as to know which data belongs to each user. So your CALENDAR table is going to need a user_id column on it. If you are using any ASP.NET web-based application framework, including MVC, you have access to the authentication provider that your application uses.
For an MVC application, your controller needs to pass the user ID (i.e. HttpContext.Current.User.Identity.Name) to the data layer, which needs to use this value in the where clause.
Trying to do this implicitly will just get you into trouble. For example, if you need to have an administrator with access to multiple users' calendars, you can't use an implicit filter. You need to have your controller tell your data layer what it wants.

Related

MySQL Query/View to pull only new data since last query

I would like to create a View that only returns new data added to the database since the last time the View was run. I know this sounds like a simple question, and there a millions of question just like it on here, but there are some restrictions in my case.
I can't use Stored Procedures, Functions or Triggers.
The user accessing the View only has read access to the database.
I posted a similar question here and was going to add an UPDATE statement to update a table with the current DateTime, and then check this table at the beginning of the View and only query after this DateTime. But the user accessing the View only has read access now.
I was also thinking there might be a type of timestamp column that updates to the current time when read with a SELECT statement, but apparently not.
Just for reference there is only ONE user accessing this view.
Any help much appreciated.
If the user only has read access to the database, then you have to store the relevant information at the application layer and not in the database. It simply is not possible to store information in the database if you don't have write access -- or at least information not part of some other process.
The recommendation would be for the application to keep track of the record returned -- keeping track of the maximum CreatedAt value or id. Then access the database using something like:
select v.*
from view v
where id > $id;
The subsequent code would update $id in the application.

Is it possible to modify the schema or instance of any database without using create, alter, delete, drop commands?

I have a web application which takes sql queries and produces the output in the form of a report. I don't want the user to MODIFY the existing database any way. To do this I decided to block all the CREATE,ALTER,DELETE,DROP commands at the web application level by just looking at the first word of the supplied query. This would stop the user from altering the existing schema or the instance of the database.
Recently I discovered that Microsoft SQL Server has the command SELECT * INTO NEW_TABLE FROM OLD_TABLE which allows us to create a copy of the the existing table. Are there any more commands of this kind which would allow us to modify the schema or instance of the existing DB by passing the web application filter ?
Any better ways to block the commands according to my requirements are also welcomed but I do not wish to take away the freedom of creating report using SQL queries at the cost of security.
Why Cannot I use Grant
I see that grant is one good option that I see from the comment as well as the answers but I will not be able to use them because the user supplies the DB details which I use to create the report along with the username and password. It is for the DB's table the user points to that I create the report
You can generate the reports from results of a query performed by a user with only read permissions. This implies management of the database connection to allow other parts of the application to manipulates the data ( you will need to connect as different users).
CREATE USER 'foouser'#'localhost' IDENTIFIED BY 'barpass';
GRANT SELECT ON db.table TO 'foouser'#'localhost';
Even if you use "SELECT * INTO NEW_TABLE FROM OLD_TABLE" you have to create the new_table first using create statement then you can use that statement.

Secure multi-tenancy in MySQL application

I have a JSP/MySQL web service where users interact with "processes" -- they can upload data, configure, view reports, etc for a given process. They can also create new processes or run reports that compare several processes.
Currently, the process id is specified in the URL (a GET parameter) so any user can interact with any process. I have been asked to add security and multi-tenancy to this service. For simplicity, let's say each tenant has full access to a set of processes, but processes may be accessible by multiple tenants.
My preferred approach:
Add a user table (PK_User_Id, password_hash, name, etc)
Add an access table (FK_User_Id, FK_Process_Id)
An SSL login page that stores the Tenant_Id in the Session
A process-select page that lets you choose a Process_Id that you have access to, and stores that in the Session
Almost every page will create its SQL queries based on the Session's Process_Id
"Cross-process" pages like Create, Select, and Compare will work off of the Session's User_Id instead
My boss thinks that this is not secure "enough" to satisfy an external code audit. He fears that a wayward developer could still write a query that exposes one customer's data to another, or something.
He wants me to also use ANSI SQL's built in ROLES (the app must stay DB agnostic) to create a db role for each user. The role will detail which tables the role has access to, which rows in shared tables, etc. This way, upon login, the Connection will be "safe" and no developer mistake can possibly cause issues.
Is this possible?
Are there such a thing as DB-agnostic "Roles" that work with MySQL?
Can the roles specify that you are allowed to add rows to a table iff the primary key is 'foo'?
Is my system "secure enough" by industry standards?
Here is what I do for MySQL multi-tenant with a single database to ensure data is private:
Create a mysql user for each tenant
Add a tenant_id column to each table
Use a trigger to automatically put the current mysql user into the tenant_id column on INSERT
Create a view for each table that only shows rows where tenant_id = mysql_user (do not include the tenant_id column in the view)
Restrict the tenant mysql user to only have access to these views
Since the application is using the tenant's mysql user there is no chance that they can accidentally get another tenant's data.
I was able to convert a large single-tenant mysql application to multi-tenant in a weekend with minimal changes. I documented the design here: https://opensource.io/it/mysql-multi-tenant/
use PostgreSQL instead, as it supports real schemas, unlike MySQL
if you have to use MySQL, do the following:
make one mysql user per tenant
add an indexed column to each table, tenant VARCHAR(16) NOT NULL
add a trigger to each table that sets tenant to the mysql connection username ON BEFORE INSERT
create a view for each table that sets WHERE tenant = mysql connection username. DO NOT include the tenant column in the select list
grant permission to the tenant user for views, but not for tables
And now the user can only see their own tenant information.
We had a similar discussion on multitenancy security and handling requests on so question. But in short I think storing tenantID in session is a huge security risk. User can go from one tenant to other and tenantID will remain the same, also tenantID should not be send through url.

Is there a way to communicate application context to a DB connection in non-Sybase DB servers (similar to set_appcontext in Sybase)?

Sybase has a way for the application to communicate "context" data - such as application's end-user name, etc.. - to the database connection session. Context data is basically just a set of key-value pairs which is stored/retrieved via set_appcontext/get_appcontext stored procs.
QUESTION:
Do other major DB servers (MSSQL/Oracle/MySQL) have a facility for communicating app context to the session similar to Sybase's set_appcontext?
Details:
One specific practical use of app context is when you have an application with middle tier connecting to the database as a very specific generic database user (examples include "webuser"/"http" for a web app back-end running on web server or "myappserver" user for an app server).
When that happens, we still want for the database session to know who the END user (e.g. actual user using the app client) is, either for access control or (more relevant to my interest), for an audit/history trigger to be able to determine which end user made the change and log that end user info into an audit table.
Please note that the info is set at the session level, which means that any inserts/updates/deletes executed within that session are able to use the context data without it being passed to each individual SQL statement - this is VERY important for, say, a trigger.
As a very specific example of why it's useful, let's say you have an app server starting a DB session on behalf of a client within which you insert/update/delete rows in 5 distinct tables. You want to have audit tables for each of those 5 tables, which include "which end user made each change" info.
Using context data, you can simply retrieve "end user" data from app context using the trigger and stored it as part of Audit table record. Without using the app context, your will need to (1) Add "end user" column to every one of those 5 tables (instead of to only audit tables) and (2) Change your app server to insert or set-on-update the value of that column in EVERY SQL statement that the app server issues. Oh, and this doesn't even get into how this can be done if you're deleting a row.
Oracle has a couple of different ways of accomplishing this. First off, you have the DBMS_APPLICATION_INFO package. Although you can use this to set arbitrary context information, it is generally used for tracing an application. You would normally set the module to be the name of the application and the action to be a description of the particular business process. You can then reference this information from V$SESSION and monitor long-running operations via V$SESSION_LONGOPS.
Oracle also has the ability to create a database object called a context. This is a more flexible way to populate session-level context. You can create a new context and then create whatever attributes you'd like within that context. And all of your code can simply reference the context. For example
SQL> create context my_ctx
2 using pkg_ctx;
Context created.
SQL> create package pkg_ctx
2 as
3 procedure set_context;
4 end;
5 /
Package created.
SQL> create or replace package body pkg_ctx
2 as
3 procedure set_context
4 as
5 begin
6 dbms_session.set_context( 'MY_CTX', 'USERNAME', 'Justin Cave' );
7 end;
8 end;
9 /
Package body created.
SQL> exec pkg_ctx.set_context;
PL/SQL procedure successfully completed.
SQL> select sys_context( 'MY_CTX', 'USERNAME' )
2 from dual;
SYS_CONTEXT('MY_CTX','USERNAME')
-------------------------------------------------------------------------------
Justin Cave
For PostgreSQL you can create a custom variable class which is a configuration setting in postgresql.conf. Something like this:
custom_variable_classes = 'myvars'
(Setting this requires a server restart if I'm not mistaken)
Now from through SQL you can read and write this in the following way:
set myvars.some_flag = 'true';
select current_setting('myvars.some_flag');
Note that you can "dynamically" defined new "variables" that are all prefixed with myvars. The individual values do not need to be declard in postgresql.conf
Originally this was intended for add-on modules to allow the definition of custom configuration options so it it a slight abuse of the feature but it should work nevertheless.

Is a simple MySql Database possible?

Steps:
I want a registered user to be able to insert values into a table.
Those values would only be able to be seen or edited by the user. (a few rows)
I have a registration/login page and insert form page complete and they can add do their respective jobs.
Here's the problem and i realize it probably a super simple answer:
How do I link the registration/login username to the values that I'm entering so that only that username has access to it?
Thanks,
Michael
You can create a MySQL user for each registered user and protect their data at the DB level. That's usually overkill for a web application.
What you probably want here is enforcing data owner at the data access layer. Associate the data to the user and restrict any data queries or updates to that user, i.e. any insert, update, select SQL statements would include the user id as a parameter.