n-tier authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll...

18
n-Tier Authentication n-Tier, or proxy, authentication is the ability for middle tier software to log onto the database using its 'own' credentials on another user's behalf, in order to perform some operation in the database. This allows us to build middle tier applications that use their own authentication scheme, perhaps via X509 certificates, or by some other single sign-on process, to securely log into a database on your behalf without having to know your database password. As far as the database is concerned, you are logged in. However, the credentials that are used to log in are not yours; they are those of the middle tier. In this chapter, we'll take a look at the features of n-Tier authentication and at how to implement this new Oracle 8i functionality in your applications. Specifically, we will: Introduce the feature and look at why you might want to use it in your applications. Develop an OCI program that will allow you to use this proxy authentication scheme to log in to the database. Investigate the ALTER USER command that enables this feature in the database. Discuss the auditing options that allow you to track the operations of the proxy account. Currently, in Oracle 8i, n-tier authentication is limited to Oracle Call Interface (OCI) programs written in C or C++. Looking ahead to Oracle 9i, this feature will be available in JDBC as well, thus greatly expanding the audience that can make use of this feature. 5254ch22.pdf 1 5254ch22.pdf 1 2/28/2005 6:52:55 PM 2/28/2005 6:52:55 PM

Upload: others

Post on 05-Jul-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

n-Tier, or proxy, authentication is the ability for middle tier software to log onto the database using its 'own' credentials on another user's behalf, in order to perform some operation in the database. This allows us to build middle tier applications that use their own authentication scheme, perhaps via X509 certificates, or by some other single sign-on process, to securely log into a database on your behalf without having to know your database password. As far as the database is concerned, you are logged in. However, the credentials that are used to log in are not yours; they are those of the middle tier. In this chapter, we'll take a look at the features of n-Tier authentication and at how to implement this new Oracle 8i functionality in your applications. Specifically, we will:

❑ Introduce the feature and look at why you might want to use it in your applications.

❑ Develop an OCI program that will allow you to use this proxy authentication scheme to log in to the database.

❑ Investigate the ALTER USER command that enables this feature in the database.

❑ Discuss the auditing options that allow you to track the operations of the proxy account. Currently, in Oracle 8i, n-tier authentication is limited to Oracle Call Interface (OCI) programs written in C or C++. Looking ahead to Oracle 9i, this feature will be available in JDBC as well, thus greatly expanding the audience that can make use of this feature.

5254ch22.pdf 15254ch22.pdf 1 2/28/2005 6:52:55 PM2/28/2005 6:52:55 PM

Page 2: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

964

Why Use n-Tier Authentication? In the days of client-server and host-based systems, authentication was easy. The client (your application) prompted the end user for their credentials (username and password) and presented these credentials to the database server. The database verified those credentials, and you were connected:

Application

DatabaseScott/Tiger

Now we have the Web and with it an n-Tier architecture where, for example, a client (your browser) presents credentials to a middle tier application server running a JavaServer Page (JSP), which in turn makes a callout to a CORBA object that finally accesses the database. The credentials presented to the middle tier may or may not be the same as the database username and password from the client server days – it might be credentials that permit access to a directory service, so the middle tier can discover who you are and what access privileges you have. It may be credentials presented in the form of an X.509 certificate that carries your identity and privileges. In any case, they are not necessarily credentials that the middle tier can use to log you into the database. The fact is that the client is no longer talking to the database directly; there are one, two, or more layers in between. You could of course, make the end user pass their database username and password to the JSP, which would pass it to the CORBA object, which would pass it to the database but that thwarts the use of other technologies and authentication mechanisms, especially single sign-on mechanisms. Consider the following example – a fairly typical web-based application today:

Web Browser Application Server

ExpenseReport

DB

Meta-LinkDB

SchedulerDB

BugDB

DirectoryService

1

2

3

4

5254ch22.pdf 25254ch22.pdf 2 2/28/2005 6:52:56 PM2/28/2005 6:52:56 PM

Page 3: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

965

The client is really just a web browser, displaying HTML, which submits requests to a web/application server over HTTP (1). The application itself resides in the web/application server, perhaps as a Java servlet, Apache module, and so on. In the above diagram, the middle tier application server uses a directory service, perhaps running LDAP, to which it transmits the credentials you supplied (2). The directory service is used as a means to authenticate the browser session. If authentication is successful, the application server is notified (3) and, finally, the application server logs in to one of many existing databases (4) to retrieve data and process transactions. The 'credentials' passed from browser to application server in (1) can take many forms – a username/password, a cookie from a single sign-on server, a digital certificate of some sorts – anything. The only thing that is generally true is that we did not pass our database username and password. The problem is, of course, that the application server needs a database login and password to authenticate the user to a back end database. Furthermore the username/password combination will be different in each case. In the above example, we have four databases:

❑ A Bug database, which might recognize me as, say, TKYTE.

❑ An Expense Report database which might recognize me as TKYTE_US.

❑ A Scheduler database which might recognize me as WEB$TKYTE.

❑ ...And so on... Stop and think for a moment – how many usernames and passwords do you have? I have at least 15 that I can remember off of the top of my head. Furthermore, although my identity in the database is never changing, my password changes frequently. Now, wouldn't it be nice if we could authenticate ourselves once – to the application server – and then the App server itself could access each of the backend databases on our behalf (in other words, by proxy), without needing to be given the specific password for each of these databases? This is what n-Tier authentication is all about. The feature that enables this in the database is a simple connection option. In Oracle 8i the ALTER USER command has been modified to support the GRANT CONNECT THROUGH clause (this is discussed in full detail later, in the Granting the Privilege section). Consider access to the Expense Report database in the above application:

Web Browser Application Server

ExpenseReport

DB

DirectoryService

TomKyte/TomKyte_password

App_Server/password as TomKyte_US

5254ch22.pdf 35254ch22.pdf 3 2/28/2005 6:52:56 PM2/28/2005 6:52:56 PM

Page 4: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

966

The directory service stores the mapping information that associates TomKyte with the database client TKYTE_US. Once that information has been successfully retrieved, the application server account (the proxy) can then log into the database, using its own credentials, on behalf of the client in the database, TKYTE_US. The application server does not need to know TKYTE_US's password. To allow this to happen, the administrator of the Expense Report database would need to grant the schema APP_SERVER permission to connect as the client:

alter user tykte_us grant connect through app_server

The application server will execute in the database with the identity and privileges of TKYTE_US, and it will be as if TKYTE_US logged directly into the database. In this manner, Oracle 8i extends the security model so that the application server can securely act on behalf of the client, without requiring the database password of the client, or requiring many privileges that allow it to access objects or procedures that it has no need to access. In addition, auditing has been extended to include operations performed by the application server on behalf of a client. That is, we can see that the application server, on behalf of a client, performed some operation (see the Auditing Proxy Accounts section for full details). We'll now move on to discuss how to implement this feature. As indicated in the introduction, this feature is currently only accessible via the Oracle Call Interface (OCI) programs written in C or C++.

The Mechanics of n-Tier Authentication In this section, we'll take one of the supplied OCI demonstration programs that implements a mini-SQL*PLUS, and modify it to use the proxy authentication scheme to log in to the database. This will give us a small, interactive SQL tool that will let us explore how this works, and what side effects we can expect to see. As a bonus, you'll have a tool that, provided you have been granted the appropriate privileges, will allow you to log in as another user and perform ad-hoc operations on their behalf, all the while being audited as yourself. You could use this, for example, to GRANT SELECT on another user's table without having to know their password. The necessary C code that we will graft into the cdemo2.c example (found in [ORACLE_HOME]\rdbms\demo) will just be a login routine. Once we've done that, we'll be able to login using OS Authentication to the SCOTT account and enable the CONNECT role, as follows:

C:\> cdemo2 / scott CONNECT

Alternatively, we can login using a username and password to a database remote to the SCOTT account and enable the roles RESOURCE and PLUSTRACE:

C:\> cdemo2 user/pass@database scott RESOURCE,PLUSTRACE

The C routine that we need to build n-Tier demonstrates how to login using this n-Tier authentication – we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just standard OCI code, no different from any other OCI program.

5254ch22.pdf 45254ch22.pdf 4 2/28/2005 6:52:56 PM2/28/2005 6:52:56 PM

Page 5: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

967

The beginning of the C code includes the standard oci.h header file found in ORACLE_HOME]\rdbms\demo. This include file holds the necessary function prototypes and defines all OCI programs. Next, we declare a couple of variables local to our login routine. Specifically, we have the normal OCI handles for a connection – but notice that we have two OCISession handles. One is for the account we will present the credentials for (login with) and the other will be for the account we want to 'become'. The remaining local variables are pretty self-explanatory – they hold the username, password, database, and all of the roles we want enabled for us:

#include <oci.h> void checkerr( OCIError * errhp, sword status); Lda_Def connect8i( int argc, char * argv[] ) { OCIEnv *environment_handle; OCIServer *data_server_handle; OCIError *error_handle; OCISvcCtx *application_server_service_handle; OCISession *first_client_session_handle; OCISession *application_server_session_handle; char *username; char *password; char *database; char temp[255]; char role_buffer[1024]; char *roles[255]; int nroles;

Next, we validate the command line arguments passed to this routine. If the number of arguments is not equal to four, we have not been passed enough information and we'll just print out a usage and exit. Otherwise, we'll parse (using the standard C function strtok) the inputs. Since strtok is destructive (it changes the string it is parsing), we copy the arguments into local variables before breaking them up:

if ( argc != 4 ) { printf( "usage: %s proxy_user/proxy_pass real_account_name role1,…\n", argv[0] ); printf( " proxy_user/proxy_pass can just be /\n" ); printf( " real_account_name is what you want to connect to\n" ); exit(1); } strcpy( temp, argv[1] ); username = strtok( temp, "/" ); password = strtok( NULL, "@" ); database = strtok( NULL, "" ); strcpy( role_buffer, argv[3] ); for( nroles = 0, roles[nroles] = strtok(role_buffer,","); roles[nroles] != NULL; nroles++, roles[nroles] = strtok(NULL,",") );

5254ch22.pdf 55254ch22.pdf 5 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 6: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

968

Now we do some general initialization and allocation of contexts. This is standard for all OCI routines:

OCIInitialize( OCI_DEFAULT, NULL, NULL, NULL, NULL ); OCIEnvInit( &environment_handle, OCI_DEFAULT, 0, NULL ); OCIHandleAlloc( (dvoid *) environment_handle, (dvoid **) &error_handle, OCI_HTYPE_ERROR, 0, NULL );

Next, we allocate and initialize the server and service contexts used by the 'application server'. In this case, the application server is going to be our mini-SQL*PLUS tool cdemo2. This code attaches us to the server but does not yet begin a session:

checkerr(error_handle, OCIHandleAlloc(environment_handle, (dvoid **)&data_server_handle, OCI_HTYPE_SERVER, 0, NULL) ); checkerr(error_handle, OCIHandleAlloc((dvoid *) environment_handle, (dvoid **) &application_server_service_handle, OCI_HTYPE_SVCCTX, 0, NULL) ); checkerr(error_handle, OCIServerAttach(data_server_handle, error_handle, (text *)database?database:"", strlen(database?database:""), 0) ); checkerr(error_handle, OCIAttrSet((dvoid *) application_server_service_handle, OCI_HTYPE_SVCCTX, (dvoid *) data_server_handle, (ub4) 0, OCI_ATTR_SERVER, error_handle) );

Now we are ready to initialize and then authenticate the application server session handle. In this case, either external authentication or username/password is being used:

checkerr(error_handle, OCIHandleAlloc((dvoid *) environment_handle, (dvoid **)&application_server_session_handle, (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0) );

5254ch22.pdf 65254ch22.pdf 6 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 7: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

969

Having initialized our session handle, we now need to add the authentication information. We permit either OS-based authentication (which would not require our application server to pass any username and password at all to the server) or standard username/password authentication. We'll put the code for username/password-based authentication first:

if (username != NULL && password != NULL && *username && *password) { checkerr(error_handle, OCIAttrSet((dvoid *) application_server_session_handle, (ub4) OCI_HTYPE_SESSION, (dvoid *) username, (ub4) strlen((char *)username), (ub4) OCI_ATTR_USERNAME, error_handle) ); checkerr( error_handle, OCIAttrSet((dvoid *) application_server_session_handle, (ub4) OCI_HTYPE_SESSION, (dvoid *) password, (ub4) strlen((char *)password), (ub4) OCI_ATTR_PASSWORD, error_handle) ); checkerr(error_handle, OCISessionBegin (application_server_service_handle, error_handle, application_server_session_handle, OCI_CRED_RDBMS, (ub4) OCI_DEFAULT) ); }

Now, the code to handle OS authentication:

else { checkerr(error_handle, OCISessionBegin(application_server_service_handle, error_handle, application_server_session_handle, OCI_CRED_EXT, OCI_DEFAULT) ); }

We are now ready to initialize the session for our client (the user who is logging in, and on whose behalf we have been trusted to execute processes). First we initialize the session:

checkerr(error_handle, OCIHandleAlloc((dvoid *) environment_handle, (dvoid **)&first_client_session_handle, (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0) );

5254ch22.pdf 75254ch22.pdf 7 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 8: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

970

Then we set the username to be associated with this session:

checkerr( error_handle, OCIAttrSet((dvoid *) first_client_session_handle, (ub4) OCI_HTYPE_SESSION, (dvoid *) argv[2], (ub4) strlen(argv[2]), OCI_ATTR_USERNAME, error_handle) );

Next, we add the list of roles we want enabled for this session – if we skip this call, all default roles for that user would be enabled:

checkerr( error_handle, OCIAttrSet((dvoid *) first_client_session_handle, (ub4) OCI_HTYPE_SESSION, (dvoid *) roles, (ub4) nroles, OCI_ATTR_INITIAL_CLIENT_ROLES, error_handle) );

Now we are ready to begin our actual session. First, we associate our client session (who we want to be seen as in the database) with our application server session (our proxy account):

checkerr(error_handle, OCIAttrSet((dvoid *) first_client_session_handle, (ub4) OCI_HTYPE_SESSION, (dvoid *) application_server_session_handle, (ub4) 0, OCI_ATTR_PROXY_CREDENTIALS, error_handle) ); checkerr(error_handle, OCIAttrSet((dvoid *)application_server_service_handle, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)first_client_session_handle, (ub4)0, (ub4)OCI_ATTR_SESSION, error_handle) );

And then we begin the session:

checkerr(error_handle, OCISessionBegin(application_server_service_handle, error_handle, first_client_session_handle, OCI_CRED_PROXY, OCI_DEFAULT) );

5254ch22.pdf 85254ch22.pdf 8 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 9: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

971

Now, since this is a version 7 OCI program (cdemo2.c is a v.7 program), we need to convert our Oracle 8i login data into something usable. Here we convert a version 8 connection into a version 7 OCI LDA (Login Data Area) and return it:

checkerr(error_handle, OCISvcCtxToLda( application_server_service_handle, error_handle, &lda ) ); return lda; }

The last bit of code is the checkerr routine that we referenced many times above. It is used to verify that the return codes from the OCI functions above indicate success, otherwise it prints out the error message and exits:

void checkerr(OCIError * errhp, sword status) { text errbuf[512]; sb4 errcode = 0; switch (status) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: (void) printf("Error - OCI_SUCCESS_WITH_INFO\n"); break; case OCI_NEED_DATA: (void) printf("Error - OCI_NEED_DATA\n"); break; case OCI_NO_DATA: (void) printf("Error - OCI_NODATA\n"); break; case OCI_ERROR: (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); (void) printf("Error - %.*s\n", 512, errbuf); exit(1); break; case OCI_INVALID_HANDLE: (void) printf("Error - OCI_INVALID_HANDLE\n"); break; case OCI_STILL_EXECUTING: (void) printf("Error - OCI_STILL_EXECUTE\n"); break; case OCI_CONTINUE: (void) printf("Error - OCI_CONTINUE\n"); break; default: break; } }

5254ch22.pdf 95254ch22.pdf 9 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 10: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

972

Now, we need to modify cdemo2.c and inject our new code. The existing code in that sample program looks like this:

... static sword numwidth = 8; main() { sword col, errno, n, ncols; text *cp; /* Connect to ORACLE. */ if (connect_user()) exit(-1); ...

The modification is very straightforward, we simply need to add the code in bold:

... static sword numwidth = 8; Lda_Def connect8i( int argc, char * argv[] ); main( int argc, char * argv[] ) { sword col, errno, n, ncols; text *cp; /* Connect to ORACLE. */ /* if (connect_user()) exit(-1); */ lda = connect8i( argc, argv ); ...

Next, add the entire contents of the code from above (the connect8i and checkerr subroutines) to the bottom of the source code file. Save that file and compile. On UNIX, the command to compile this will be:

$ make -f $ORACLE_HOME/rdbms/demo/demo_rdbms.mk cdemo2

On Windows NT, I used this makefile:

CPU=i386 WORK_DIR = .\ !include <\msdev\include\win32.mak> OBJDIR = $(WORK_DIR)\ # EXEDIR = $(WORK_DIR)\ # dir where all the .exe will be put

5254ch22.pdf 105254ch22.pdf 10 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 11: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

973

ORACLE_HOME = \oracle TARGET = $(EXEDIR)cdemo2.exe SAMPLEOBJS = cdemo2.obj LOCAL_DEFINE = -DWIN_NT SYSLIBS = \msdev\lib\msvcrt.lib \ \msdev\lib\oldnames.lib \ \msdev\lib\kernel32.lib \ \msdev\lib\advapi32.lib \ \msdev\lib\wsock32.lib NTUSER32LIBS = \msdev\lib\user32.lib \ \msdev\lib\advapi32.lib \ \msdev\lib\libc.lib SQLLIB = $(ORACLE_HOME)\oci\lib\msvc\oci.lib INCLS = -I\msdev\include \ -I$(ORACLE_HOME)\oci\include CFLAGS = $(cdebug) $(cflags) $(INCLS) $(LOCAL_DEFINE) LINKOPT = /nologo /subsystem:console /machine:I386 /nodefaultlib $(TARGET): $(SAMPLEOBJS) $(SQLLIB) $(link) $(LINKOPT) \ -out:$(TARGET) $(SAMPLEOBJS) \ $(NTUSER32LIBS) \ $(SYSLIBS) \ $(SQLLIB)

And then just used nmake to compile it:

c:\oracle\rdbms\demo>nmake

Now we are ready to try it:

c:\oracle\rdbms\demo>cdemo2 tkyte/tkyte scott connect,resource Error - ORA-28150: proxy not authorized to connect as client

So, we do not have success yet but we are very close. We need to give our proxy (TKYTE) the authority to connect as the database client (SCOTT). Log into SQL*PLUS and issue:

sys@TKYTE816> alter user scott grant connect through tkyte; User altered.

We'll explain more about that new command in a moment, along with all of its options. Now we just want to see this work. Notice the bolded prompt – I am not in SQL*PLUS here, I am in the cdemo2 application, it just looks a lot like SQL*PLUS:

5254ch22.pdf 115254ch22.pdf 11 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 12: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

974

c:\oracle\rdbms\demo>cdemo2 tkyte/tkyte scott connect,resource OCISQL> SELECT user, substr(sys_context('userenv','proxy_user'),1,30) 2 FROM dual; USER SUBSTR(SYS_CONTEXT('USERENV','PRO ------------------------------ ------------------------------ SCOTT TKYTE 1 row processed. OCISQL> select * from session_roles; ROLE ------------------------------ CONNECT RESOURCE 2 rows processed. OCISQL> select distinct authentication_type from v$session_connect_info 2 where sid = ( select sid from v$mystat where rownum =1 ); AUTHENTICATION_TYPE -------- PROXY 1 row processed. OCISQL> exit C:\oracle\RDBMS\demo>

That's it. We've successfully logged in as SCOTT without knowing SCOTT's password. Additionally, we've seen how we can verify that we are proxied in, by comparing USER to SYS_CONTEXT's PROXY_USER, or by looking in the V$SESSION_CONNECT_INFO view. Also, we can clearly see that the roles CONNECT and RESOURCE are enabled. If we connected like this:

c:\oracle\rdbms\demo>cdemo2 tkyte/tkyte scott connect OCISQL> select * from session_roles; ROLE ------------------------------ CONNECT 1 row processed.

We can see that only CONNECT is enabled – we control what roles the 'application server' enables.

5254ch22.pdf 125254ch22.pdf 12 2/28/2005 6:52:57 PM2/28/2005 6:52:57 PM

Page 13: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

975

Granting the Privilege The basic syntax of the ALTER USER command is as follows:

Alter user <username> grant connect through <proxy user><,proxy user>...

This gives the usernames listed in the proxy user list the ability to connect as username. By default, these listed users will have all of that user's roles available to them. There is a variation of this command:

Alter user <username> grant connect through <proxy> WITH NONE;

This allows the proxy account to connect as username but only with their base privileges – no roles will be enabled. Additionally, we can use:

Alter user <username> grant connect through <proxy> ROLE rolename,rolename,...

or:

Alter user <username> grant connect through <proxy> ROLE ALL EXCEPT rolename,rolename,...

The purpose of the above two statements would be to give a proxy account the ability to connect as a given user, but only with certain application roles enabled. You do not have to give the application server proxy account all of the privileges, just the necessary roles to accomplish the job. By default, Oracle tries to enable all default roles for the user and the PUBLIC role. This would be appropriate if the application server was only allowed to assume the HR role for a given user, and none of the other application roles that user was able to use.

There is, of course, also a method to revoke:

Alter user <username> REVOKE connect through <proxy user><,proxy user>...

There is an administrative view, PROXY_USERS, which you may use to review all granted proxy accounts. Right now, given that we issued the ALTER user SCOTT GRANT CONNECT through tkyte; command – our PROXY_USERS view has:

TKYTE@TKYTE816> select * from proxy_users; PROXY CLIENT ROLE FLAGS -------- -------- ---------- ----------------------------------- TKYTE SCOTT PROXY MAY ACTIVATE ALL CLIENT ROLES

5254ch22.pdf 135254ch22.pdf 13 2/28/2005 6:52:58 PM2/28/2005 6:52:58 PM

Page 14: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

976

Auditing Proxy Accounts The new syntax of the audit command with regards to proxy accounts is:

AUDIT <operation> BY <proxy>, <proxy> ... ON BEHALF OF <client>, <client>..; or:

AUDIT <operation> BY <proxy>, <proxy> ON BEHALF OF ANY; The new part is the BY <proxy> and ON BEHALF OF. It allows us to specifically audit operations performed by specific proxy users on behalf of any specific or all accounts. For example, suppose you enabled auditing by setting AUDIT_TRAIL=TRUE in your init.ora and restarting the instance. We could then use:

sys@TKYTE816> audit connect by tkyte on behalf of scott; Audit succeeded.

Now, if I use our modified cdemo2.c to connect:

C:\oracle\RDBMS\demo>cdemo2 tkyte/tkyte scott connect OCISQL> exit

I'll find this record in DBA_AUDIT_TRAIL:

OS_USERNAME : Thomas?Kyte USERNAME : SCOTT USERHOST : TERMINAL : TKYTE-DELL TIMESTAMP : 08-may-2001 19:19:29 OWNER : OBJ_NAME : ACTION : 101 ACTION_NAME : LOGOFF NEW_OWNER : NEW_NAME : OBJ_PRIVILEGE : SYS_PRIVILEGE : ADMIN_OPTION : GRANTEE : AUDIT_OPTION : SES_ACTIONS : LOGOFF_TIME : 08-may-2001 19:19:30 LOGOFF_LREAD : 23 LOGOFF_PREAD : 0 LOGOFF_LWRITE : 6 LOGOFF_DLOCK : 0 COMMENT_TEXT : Authenticated by: PROXY: TKYTE SESSIONID : 8234 ENTRYID : 1 STATEMENTID : 1 RETURNCODE : 0 PRIV_USED : CREATE SESSION

5254ch22.pdf 145254ch22.pdf 14 2/28/2005 6:52:58 PM2/28/2005 6:52:58 PM

Page 15: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

977

It is interesting to note that if either SCOTT or TKYTE connects via SQL*PLUS, no audit trail record is created. Auditing is strictly limited to:

connect by tkyte on behalf of scott;

I can still audit connects by TKYTE or SCOTT if I want, I just chose not to in this case. This just shows that we can still have accountability in the database (we can tell it was SCOTT that performed some action), but we can also tell when it was an application server executing on behalf of SCOTT.

Caveats In general, n-Tier authentication works exactly like you might expect it to. If you connect:

C:\oracle\RDBMS\demo>cdemo2 tkyte/tkyte scott connect

It will be as if SCOTT logged in directly. Features like Invoker and Definer Rights (Chapter 23) work as if SCOTT logged in. Fine Grained Access Control (Chapter 21) work as if SCOTT logged in. Login triggers for SCOTT will fire as expected. And so on. I have not found any feature to be negatively affected by the use of n-Tier authentication. There is one implementation detail that might be an issue, however. When using n-Tier authentication, the server will enable a set of roles for you. If you use the OCI_ATTR_INITIAL_CLIENT_ROLES attribute that we used above, you might expect this set of roles to be limited only to those you specify. However, the roles that have been granted to PUBLIC are always enabled as well. For example, if we grant the PLUSTRACE role to PUBLIC (PLUSTRACE is the AUTOTRACE role we've been making use of throughout this book to do performance tracing in SQL*PLUS):

sys@TKYTE816> grant plustrace to public; Grant succeeded.

Now, when we connect with our mini-SQL*PLUS:

c:\oracle\rdbms\demo>cdemo2 tkyte/tkyte scott connect OCISQL> select * from session_roles; ROLE ------------------------------ CONNECT PLUSTRACE 2 rows processed.

You'll notice that in addition to the CONNECT role being enabled, the PLUSTRACE role is also enabled. This might not seem like a bad thing at first. However, if you've used the ALTER USER command to pass on only a few roles to some user:

sys@TKYTE816> alter user scott grant connect through tkyte with role CONNECT; User altered.

5254ch22.pdf 155254ch22.pdf 15 2/28/2005 6:52:58 PM2/28/2005 6:52:58 PM

Page 16: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

Chapter 22

978

You'll now discover that:

c:\oracle\rdbms\demo>cdemo2 tkyte/tkyte scott connect Error - ORA-28156: Proxy user 'TKYTE' not authorized to set role 'PLUSTRACE' for client 'SCOTT'

The user, TKYTE, is not allowed to enable this role when connecting on SCOTT's behalf. The only solutions to this issue are:

1. Do not grant roles to PUBLIC

2. Or, always add that role to the list of roles in the ALTER USER command.

For example, if we issue:

sys@TKYTE816> alter user scott grant connect through tkyte with role 2 connect, plustrace; User altered.

Then the following works as expected:

c:\oracle\rdbms\demo>cdemo2 tkyte/tkyte scott connect OCISQL> select * from session_roles; ROLE ------------------------------ CONNECT PLUSTRACE

Summary In this chapter, we learned about the proxy authentication or n-Tier authentication capabilities available to us when programming in OCI. This feature allows a middle tier application server to act as a trusted agent into the database, on behalf of a client known to the application. We have seen how Oracle allows us to restrict the set of roles available to the application server proxy account, so that the proxy account can only perform application specific operations. Further, we have seen how auditing has been enhanced to support this new feature. We can audit actions specifically performed by proxy accounts on behalf of any given user or all users. We can clearly see when a given user, via the application proxy account, performed an action, and when it was done by the user directly. We modified one of Oracle's simple demonstration programs to provide us with a simple SQL*PLUS-like environment to test this feature. The environment it provides is optimal for testing out various pieces of this functionality, and will help you see how it works interactively.

5254ch22.pdf 165254ch22.pdf 16 2/28/2005 6:52:58 PM2/28/2005 6:52:58 PM

Page 17: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just

n-Tier Authentication

979

5254ch22.pdf 175254ch22.pdf 17 2/28/2005 6:52:58 PM2/28/2005 6:52:58 PM

Page 18: n-Tier Authenticationextras.springer.com/2005/978-1-59059-525-1/5254ch22final.pdf · we'll take a look at it piecebypiece. Once we are logged in, the rest of the application is just