Pass through Query Fails with Stored Procedure using Linked Servers - sql-server

I've created a stored procedure in SQL Server that in turn is using a linked server to query two databases. The results are returned as expected in Query Analyzer, but when I try running the same stored procedure using a pass-through query in Access I get an authentication error.
Access has no problem quering either database when I use the passthrough and either DSN, it's only when I try to execute the stored procedure.
It almost seems like the DSN connection can't pass on the credentials to the linked server via the current DSN server.
The user is a member of domain admins, has full rights to both sql servers and I'm using Integrated Security on both DSNs.

Sounds like a classic double hop issue. The article Configuring Linked Servers for Delegation discusses how to work around this. But you'll note that one of the first requirements listed is:
The user Active Directory property, Account is sensitive and cannot be delegated, must not be selected.
which is almost certainly selected for the domain admin account (or at least, it should be in a well run domain)

Related

SQL Server Grant Remote access to execute Stored Procedures within a given Schema

I am a developer for a hospital which uses software provided by a 3rd party vendor which hosts Sql Server for us. We have a local instance of Sql Server 2012 which has a linked server to their Sql Server instance. Within our instance of Sql Server we can see all of the Views and Tables that have been assigned to us but none of the stored procedures.
However, I have been given a Citrix connection which allows me to access Sql Server on their network. From here, I can create, alter and execute stored procedures in the [CUSTOMER] schema they created for this purposes (we can only execute procs in dbo, but not alter or create).
The vendor is now trying to give me access to execute stored procedures we created in [CUSTOMER] through our linked server. However, it's not working. They say they have given permission to my user as well as the user listed under the Security tab of Linked Server Properties in "Be made using this security context".
Properties for RPC and RPC Out are set to true.
No Sp's show up under the linked server node (no "programmability" node at all). And when I try to execute my proc like this: [remoteserver.ip.address].[remoteDbInstance].[Customer].[extr_myProc], I get the following error:
"Cannot find the object "extr_myProc" because it does not exist or you do not have permissions."
I suspect there's an issue on their side but our contact at the vendor says they've done everything. Is there something else I should be doing on my side though?
I suspect that there's more than one measure a vendor can take to lock down stored procs over a linked server and all their support staff did was to make sure [CUSTOMER] was executable for our users, but another setting is blocking it specifically for linked servers.
Is there something I can suggest to their support staff to look at for us that can hide stored procs from a user, but only over a linked server?
Thanks!

XP_DirTree in SQL Server

Variations to this have been asked. I have no problem searching a local directory with the below piece of code.
EXEC MASTER.sys.xp_dirtree 'C:\', 1, 1
When I switch the path to a network location the results are empty.
EXEC MASTER.sys.xp_dirtree '\\Server\Folder', 1, 1
I first thought maybe it was something to do with permissions. I added the SQL Server Service to the ACL list on the shared volume as well as the security group.
Any help or direction to point me in is greatly appreciated or even another way to get a list of files in a directory and sub directories.
[Edited]
The two things to look out for are:
Make certain that the Log On account for the SQL Server service (the service typically listed as "SQL Server (MSSQLSERVER)" in the Services list) has rights to that network share.
UPDATE
The problem ended up being that the O.P. was running the SQL Server service as a local system account. So, the O.P. created a domain account for SQL Server, assigned that new domain account as the Log On As account for the SQL Server service, and granted that domain account the proper NTFS permissions.
Please note that this might have also been fixable while keeping the SQL Service running as a local system account by adding the server itself that SQL Server is running on to the NTFS permissions. This should usually be possible by specifying the server name followed by a dollar sign ($). For example: MySqlServer01$. Of course, this then gives that NTFS permission to all services on that server that are running as a local system account, and this might not be desirable. Hence, it is still preferable to create a domain account for the SQL Server service to run as (which is a good practice in any case!).
It sounds like this has been done, so it should be tested by logging onto windows directly as that account and attempting to go to that specific network path.
Make sure that the Login in SQL Server that is executing xp_dirtree has "sysadmin" rights:
This can be done directly by adding the account to the sysadmin server role, or
Sign a stored procedure that runs xp_dirtree:
Create a certificate in [master]
Create a login based on that certificate
Add the certificate-based login to the sysadmin server role
Backup the certificate
Restore the certificate into whatever database has, or will have, the stored procedure that runs xp_dirtree
Sign the stored procedure that runs xp_dirtree, using ADD SIGNATURE and the certificate that was just restored
GRANT EXECUTE on that stored procedure to the user(s) and/or role(s) that should be executing this.
Just to have it stated, another option is to do away with xp_dirtree altogether and instead use SQLCLR. There is probably sample C# code on various blogs. There are also a few CodePlex projects that have file system functions and might also provide a pre-compiled assembly for those that don't want to deal with compiling. And, there is also the SQL# library that has several filesystem functions including File_GetDirectoryListing which is a TVF (meaning: you can use it in a SELECT statement with a WHERE condition rather than needing to dump all columns and all rows into a temp table first). It is also fully-streamed which means it is very fast, even for 100k or more files. Please note that the FILE_* functions are only in the Full version (i.e. not free) and I am the creator of SQL#, but it does handle this situation quite nicely.

SQL Server connection on distributed Access front end

I'm working on an application right now that requires a link to a couple of SQL Server tables. My windows network account has permission to connect to this server, but I am not going to be the only one using this application. I'm going to send it out for people to save to their PC or just put it on the company shared drive to use (I know, that's asking for problems sometimes). It's inconvenient to make a windows account for users to share because they would need to log out and in to use the app, so I was wondering if the application or ODBC connection file itself can store the credentials to access the table.
Should I configure the connection object to use something other than the windows login information (maybe a SQL server username/password), and just store the connection object in a shared location? I don't have much experience with this and haven't tried out many different solutions and I am open to suggestions.
Thank you for the suggestions
As suggested in a comment to the question, one solution would be to
create a User Group in Windows on the SQL Server,
create a SQL Server login for that group,
assign permissions within SQL Server to that login,
and then just add or remove particular Windows Users from that group as required.
That way you don't need to mess with the various SQL Server permissions for each database user, and your application can connect to the SQL Server using Windows Authentication so you don't have to mess with saved SQL Server credentials (in connection strings, or elsewhere).
You certainly can specify the username & password in the connection string -- ConnectionStrings.Com is highly recommended if you are having trouble with connection strings -- their first example for Sql Server is
Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;
The issue is security, if users can see this in a configuration file, they can do anything that account can do. You have to handle security within you application if you do this. Most apps that handle their own security have to create users and passwords in a database table (best not to store password at all, much less plaintext -- a one way hash is recommended).
One good strategy is the create a "login user" account with well known name and password, grant no read / write, etc. for that account at all, and grant execute access to single stored proc
IsLoginPermitted #ID, #PASS
When successful, IsLoginPermitted returns the ID & PASS for subsequent use (of course these are hidden from the user) and you create your new connection string based on these.

SQL Server: Checking role membership

In SQL Server I have a many to many relationship between items and active directory groups. I want to build a query, that based on a supplied active directory user, I would be able to query for all items associated to an active directory group if the user is a member of the group.
I went down the road of using IS_Member, but that only works for the currently connected user. The stored procedure will be called by an asp.net web app, which currently connects with a specific sql user account. I don't think I can connect using integrated authentication and impersonation in the web app, because I don't beleive our infrastructure configuration will allow delegation from the user machine, through the web server, then to the db server (3 hop issue).
What can I do here?
Write a C# or VB.NET .exe that queries AD and populates a table in the database with all the users/groups and call it from a SQL job that you execute daily. Then just use the synched up table data to do the comparisons. This way you can avoid all the other complexity of trying to do it on the fly. Group membership doesn't change that often. Even if something changed in AD you can just manually run your "sync job" and things would be ok. You can use Windows.Identity() or whatever it is from ASP.NET to check the username.
The issue you describe is a classic double-hop scenario, which can be (eventually) resolved through the painstaking process known as Kerberos configuration. A lazier workaround would involve passing the credentials from the asp.net application as a variable to a SQL query on your database.
If the SQL Server has the LDAP Server configured as a linked server, you could rewrite your stored procedures to accept the user as an input variable and check to see if the user is a member of an AD group before proceeding. Consider incorporating OPENQUERY into your stored procedures as shown below:
CREATE PROCEDURE CheckAccess
#CurrentUser varchar(max)
AS
IF #CurrentUser IN
(
SELECT CN
FROM OPENQUERY(ADSI,'<LDAP://DC=Your,DC=DomainComponent,DC=com>;(&(CN=*)
(memberOf=CN=YourADGroupName,OU=Your,OU=OrganizationalUnit,OU=Name,DC=Your,DC=DomainComponent,DC=com));CN')
)
THEN
SELECT 'Authorized User'
ELSE
SELECT 'Unauthorized User'
END
If you can, consult with your LDAP admins to make sure you get the group's correct domainComponents and organizationalUnits to tweak the OPENQUERY. One drawback to this is that it can take a while to query your AD group, obviously depending on the size of membership. It can be a pain, but as long as your app can pass the user as a variable, you can leverage OPENQUERY or even query sys.database_principals to check their access.

How to pass out-of-band (current User Id) data to SQL Server 2008

We have a web application that uses forms authentication to authenticate a user based on a user table in the database. (I.e. no active directory or SQL server user accounts are involved here). The web application accesses the SQL server using a service account. However, for auditing, authorization and other purposes, our stored procedures need to know for which user any given operation is being executed.
In a previous life, I worked with a similar situation using an Oracle database. In this scenario, every time we opened a connection, we first called an Oracle build in procedure to set a connection scoped context variable. This variable contained the user id for the user that would be using the connection. Then all stored procedures that needed to know the current user would check the context variable.
Conceptually this worked a lot like pushing user information onto the CallContext before making a remote call.
My question is, is there any similar mechanism in Microsoft SQL server?
Obvioulsy, if I must, I can pass the UserId as an argument to every single stored procedure, but that is exactly what I am trying to avoid.
Use SET CONTEXT_INFO and CONTEXT_INFO(). See Using Session Context Information.
What you can do is create users within the database (without Server logins) and give them appropriate permissions. After that, what you do is an "execute as" statement and then the user context for your database calls will be as if the user called it. Example:
EXECUTE AS USER = 'user2';
EXECUTE usp_insert_stuff #params;
REVERT;
Downside: you have to set up SQL security and manage users
Upside: Users cannot connect directly to SQL Server and you get auditing.
Reference here:
http://msdn.microsoft.com/en-us/library/ms188354.aspx
See examples towards the bottom of the page.

Resources