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 2/28/2005 6:52:55 PM Chapter 22 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: Scott/Tiger Database Application 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: Directory Service Bug DB 2 3 Scheduler DB 1 Web Browser 4 Expense Report DB Application Server Meta-Link DB 964 5254ch22.pdf 2 2/28/2005 6:52:56 PM n-Tier Authentication 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: Directory Service TomKyte/ TomKyte_password Web Browser App_Server/pass word as TomKyte_US Expense Report DB Application Server 965 5254ch22.pdf 3 2/28/2005 6:52:56 PM Chapter 22 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 miniSQL*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. 966 5254ch22.pdf 4 2/28/2005 6:52:56 PM n-Tier Authentication 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 char char char char char int *username; *password; *database; temp[255]; role_buffer[1024]; *roles[255]; 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,",") ); 967 5254ch22.pdf 5 2/28/2005 6:52:57 PM Chapter 22 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) ); 968 5254ch22.pdf 6 2/28/2005 6:52:57 PM n-Tier Authentication 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) ); 969 5254ch22.pdf 7 2/28/2005 6:52:57 PM Chapter 22 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) ); 970 5254ch22.pdf 8 2/28/2005 6:52:57 PM n-Tier Authentication 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; } } 971 5254ch22.pdf 9 2/28/2005 6:52:57 PM Chapter 22 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 EXEDIR = = $(WORK_DIR)\ $(WORK_DIR)\ # # dir where all the .exe will be put 972 5254ch22.pdf 10 2/28/2005 6:52:57 PM n-Tier Authentication 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 SQLLIB = \msdev\lib\user32.lib \ \msdev\lib\advapi32.lib \ \msdev\lib\libc.lib = $(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: 973 5254ch22.pdf 11 2/28/2005 6:52:57 PM Chapter 22 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. 974 5254ch22.pdf 12 2/28/2005 6:52:57 PM n-Tier Authentication 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 975 5254ch22.pdf 13 2/28/2005 6:52:58 PM Chapter 22 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 USERNAME USERHOST TERMINAL TIMESTAMP OWNER OBJ_NAME ACTION ACTION_NAME NEW_OWNER NEW_NAME OBJ_PRIVILEGE SYS_PRIVILEGE ADMIN_OPTION GRANTEE AUDIT_OPTION SES_ACTIONS LOGOFF_TIME LOGOFF_LREAD LOGOFF_PREAD LOGOFF_LWRITE LOGOFF_DLOCK COMMENT_TEXT SESSIONID ENTRYID STATEMENTID RETURNCODE PRIV_USED : : : : : : : : : : : : : : : : : : : : : : : : : : : : Thomas?Kyte SCOTT TKYTE-DELL 08-may-2001 19:19:29 101 LOGOFF 08-may-2001 19:19:30 23 0 6 0 Authenticated by: PROXY: TKYTE 8234 1 1 0 CREATE SESSION 976 5254ch22.pdf 14 2/28/2005 6:52:58 PM n-Tier Authentication 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. 977 5254ch22.pdf 15 2/28/2005 6:52:58 PM Chapter 22 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*PLUSlike 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. 978 5254ch22.pdf 16 2/28/2005 6:52:58 PM n-Tier Authentication 979 5254ch22.pdf 17 2/28/2005 6:52:58 PM