4

I have a stored procedure called 'authenticate' that returns me the user profile record if provided correct username and password. Now I am trying to get all users in system if 'authenticate' stored procedure returned me a record otherwise return nothing. I am trying something like this:

IF EXISTS EXECUTE authenticate @UserName, @Password
BEGIN    
    SELECT * from Users;
END

I am getting error: Incorrect syntax near the keyword 'EXECUTE'. Any ideas what am I doing wrong?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
shaffooo
  • 1,478
  • 23
  • 28
  • 1
    How much control do you have on the design? You could alter `Authenticate` to be a table valued function, then you could use `IF EXISTS (SELECT 1 FROM Authenticate (@UserName, @Password)`. If you still need the SP for other areas, you could just name the function something else, and have the SP call the function to save maintaining two scripts. – GarethD Mar 07 '16 at 17:44

3 Answers3

3

EXISTS takes a SELECT subquery not the results of a stored procedure. See MSDN. You will need to either replicate your SELECT from authenticate in your EXISTS statement or populate a table with the results prior to the EXISTS. e.g.

INSERT INTO #authenticate (col1, col2, col3)
EXEC authenticate @UserName, @Password

IF EXISTS (SELECT 1 FROM #authenticate)
BEGIN    
    SELECT * from Users;
END
strickt01
  • 3,959
  • 1
  • 17
  • 32
  • I would like to go that way but I really don't want to add all the fields again for #authenticate table. is it possible for us to create temporary table without specifying column names i.e. can it somehow deduce the column names from the result of stored procedure? – shaffooo Mar 07 '16 at 17:50
  • You'd need to use `OPENROWSET`: see [this old answer](http://stackoverflow.com/questions/20280111/exec-stored-procedure-into-dynamic-temp-table) – strickt01 Mar 07 '16 at 18:16
3

You can transform your procedure into function:

create function dbo.authenticate(@UserName varchar(50), @Password varchar(50))
returns @found table(userName varchar(50), userPass varchar(50)) as
begin
  -- some of your internal table
  declare @user table (userName varchar(50), userPass varchar(50));
  insert into @user values ('John', '123'), ('Jack', '345');

  insert into @found (userName, userPass)
    select
      u.userName, u.userPass
    from
      @user u
    where
      u.userName = @UserName and u.userPass = @Password
  ;

  return;

end;

go

if exists(select * from dbo.authenticate('John', '123')) begin
  print 'exists';
end;
Slava N.
  • 596
  • 4
  • 6
  • I think its better solution given the constraints but can I return the @found table without defining its column names. I really want to return the result of "select a row from users table where username and password match". – shaffooo Mar 07 '16 at 17:58
  • I used CREATE TO script from SQL Management Studio for @found table column names and its working as expected. Its ok to do so because you have to create those fields inside the function one time only and then use it in IF EXISTS any where which is what I needed from this.Thanks. – shaffooo Mar 07 '16 at 18:17
0

I see several design problems:

1

Method "Authenticate" returns some rowset. Why? It is called "authenticate" - not "SelectAuthenticatedUserInfo". I assume this procedure does more than one job.

Split it to real authentication method which gives probably an output variable with session-id or bit flag yes/no = ok/fault. And create another procedure something like dbo.SelectAuthUserProfile which is called once at application start, calls from within dbo.Authenticate and if it succeeds - returns rowset with according data.

2

This select looks like a regular work, I mean - it's not likely a one-time "low-level" work on app start or sign-in/sign-out. Why are you performing authenticate method? Are you serious that you want to pass username and (!) password every time you want to select some data? Authentication is a one-time job per session (or even some longer scenarios).

Do authenticate your user, then just check if he is already authenticated or not. Store your session data somewhere, pass only a key or something (or even don't pass anything - there are some tricks with ## or # tables, spid+login time and so on).

3

It does not seem to me that every user may view contents of Users table. Access can be controlled by internal sql-server's tools.

Create schema for admin-specific stored procs, create role for such super-users, grant'em this schema's procedures. This will exclude any possibility for a regular user to execute such proc.

4

Think further of managing access to different parts of your system. To the question "Is this user permitted to perform such an action?" you are trying to answer "He is authenticated!" Okay, authenticated. So what? Does he have a permission or not?

Authenticate user once, then - control his permissions. There cannot be "authenticate" method inside of a regular proc. But "IsPermitted" I guess is supposed to be. (this item correlates with 1st - to many responsibilities for a proc)

5

Furthermore, think of this: permitted to see these orders, but not permitted to see those. Can you arrange it with a proc call like if exec then?

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39
  • Thanks for your detailed suggestion. Why passing a key back and forth is fine but not username and password? I am retrieving user profile on authenticate because then you save this information on client side to make further calls. Why make another call after authentication to get user profile? I do agree on creating a authenticate function for yes/no but from client then we will have to call SelectAuthUserProfile and use authenticate within this procedure, right? We cannot use authenticate on itself to get any useful information for the user. We do have roles table. – shaffooo Mar 08 '16 at 14:55
  • Is your "role" table a part of MS SQL SERVER security system I was talking about? If authenticating user with login-password on every db call is okay to you then probably my post is not related to your type of system. – Ivan Starostin Mar 08 '16 at 15:16