Oracle9i Servlet Engine Developer's Guide Release 1 (9.0.1) Part Number A90213-02 |
|
This chapter covers basic aspects of security for the Oracle Servlet Engine, running in the Oracle Java Virtual Machine. This chapter focuses on security as established using the session shell tool. Chapter 8, "Oracle WAR Deployment" describes those aspects of security that are implemented using Web Archive (WAR) deployment files.
The topics discussed in this chapter are:
Security for the OSE/OJVM includes three security mechanisms:
The first two aspects of OSE/OJVM security and the third are virtually orthogonal. The slight exception to their almost total independence comes when an HTTP security realm type uses database schemas as the principals. This is described in "The DBUSER Type".
This chapter first describes the JNDI protection mechanism that is based on Oracle database security, then describes how HTTP security is implemented by the OSE/OJVM. Although knowledge about basic database security and Java security in the database is helpful in reading this chapter, it is not essential. If you need more information on these topics see the following Oracle guides:
This Guide assumes some basic knowledge about HTTP security. For more information, you can look up the HTTP 1.1 specification RFC, which is available at
http://www.w3.org/Protocols/rfc2068/rfc2068
More accessible documentation about HTTP security is available in any of the trade press books that cover the Apache Web server. Two such are
To create entries in the OSE/OJVM JNDI namespace, you must be in possession of a valid Oracle database schema name and password. Using the session shell tool requires a connection to a database session, which requires a database server login. For example, to create a Web service you must connect to the OSE session shell as the database schema SYS. If SYS then changes ownership of the service root to schema HR, then you have to be connected through the session shell as HR to do things like publish servlets, create HTTP security objects such as realms, add principals to realms, and so on.
When a client accesses the OSE, from a Web browser for example, and runs a servlet that is owned by a schema, then that servlet runs with all the database privileges associated with that schema. The servlet can query database tables or other database objects, update tables and other objects, run stored procedures, and do all the other things that a database user can do, exactly in accord with the database permissions that the schema possesses.
What HTTP security allows you to do is permit and restrict access to servlets and other JNDI objects (JSPs, text files, and so on) above and beyond the database access permissions. For example, you might not want all Web browser users to be able to access servlets that in turn access the HR database schema. So you can add authentication and authorization requirements to the HR servlets using HTTP security, which is described in "HTTP Security".
JNDI security is implemented using a UNIX-like permissions scheme. Each OSE JNDI object, for example a published servlet in a named_servlets
context, has an owner. The owner has a combination of three types of permission: read, write, and execute. The exact semantics of each permission type are described in the Oracle9i Java Tools Reference. In summary, read permission allows the session shell user to "read" the object: list it, get its properties, and actually read it to the extent that it is readable. Write permission allows the user to modify the object: delete it, substitute another object, write it to the extent it is writable (a text file, for example), add objects or properties to it (if it is a context, or a realm). Execute permission allows the user to have the OSE activate the object, if it is for example a servlet, or to search the object, if it is a context.
In addition to owner's permissions, each OSE JNDI object has an access control list. (This is where JNDI permissions differ somewhat from UNIX permissions, as the UNIX group concept is not directly implemented in the OSE JNDI namespace implementation.) So an object can have a list of database users (schemas), each of which can have a different set of access permissions.
Normally, OSE JNDI objects in a servlet context inherit the ownership and permissions of the owner of the Web domain. However in many cases it is desirable for the owner of a domain to grant the right for other schemas to publish servlet contexts in that domain, and to then effectively publish servlets in those contexts. For example, the HR schema owns a domain HRRoot
. HR can grant the schema BENEFITS the right to publish servlets in its own context in that domain.
In the normal course of events, the OSE would use the domain owner's database permissions when executing servlets in a servlet context in the domain. However, the domain owner can establish that a servlet context is to run with the database permissions of the servlet context owner. This is set by adding a group property to the domain config
object, as the follow example, for the HRRoot
service shows
$ cd /HRRoot $ addgroupentry config context.properties context.runAsOwner true
OSE JNDI object ownership is controlled using the session shell chown
command, and permissions and access control lists are controlled by the chmod
command. These commands are documented in the Oracle9i Java Tools Reference.
HTTP security allows you to extend and refine the basic security provided by the JNDI/Oracle database security model. The OSE/OJVM supports the most popular aspects of the HTTP security model, including BASIC and DIGEST authentication, as well as authentication using Oracle Single Sign-On (OSSO).
While the database and JNDI security covers for the most part access to database objects, HTTP security determines who can access servlets from a Web client, and what HTTP requests clients can use.
Access to a protected Web service resource involves authentication and authorization. Authentication is the validation of submitted credentials, which establish that a client is known and validated by the system. Authorization is the determination that an authenticated user is allowed to perform the requested action.
There are four steps in setting up HTTP security for a Web application:
Follow these steps to ensure that the correct base information is established to define HTTP security for your Web resources. If one or more of these steps is not followed, security can become either non-existent, or access to protected resources can be denied to users who should have it.
Principal is the generic term for either a servlet engine user, or a group of users. A group contains users or other groups. The realm is an object in the Web service that contains and organizes the declared principals. Figure 7-1 shows that the realm
objects are at the top level of the Web service, in the realms
context, which is at the same level as the config
object for the Web service.
Text description of the illustration JNDI_Realm.gif
Groups contain other principals (users or other groups). Individual members of a group inherit the permissions of the group object.
Users are single objects. Unlike a group, there are no subsets of other principals belonging to a user.
The realm is the basic unit of HTTP security in the OSE/OJVM. Each realm defines a separate set of principals. A Web service can contain multiple realms, as shown in Figure 7-1. The realm is the source of the valid set of principals, and the types of principals that are handed to the server. The realm is the source of all principals, and it also determines what kind of credentials are to be used to authenticate a principal.
Each realm has a type, which determines the way the realm information originates and the way it is stored. There are four types of realms, which are:
A realm that has the DBUSER type derives principal definitions and permissions from the users and roles defined in the database. The implications of this are:
realm
commands.
create user "steve" identified by boss;
In this case the schema, and hence the principal name, is "steve"--lowercase.
These realm types behave the same, only the way the information about principals and groups is stored differs. You manage realms of this type using the session shell realm
commands.
The OSSO realm type is described in "Configuring mod_osso".
The session shell realm
commands are the tools that you use to establish, configure, and remove realms. Use these session shell commands to:
realm
realm list ...
realm publish ...
realm user ...
realm group ...
realm parent ...
realm map ...
realm perm ...
This chapter lists some common ways to use the realm
commands. Complete documentation for the realm
commands is available in the Oracle9i Java Tools Reference.
To create a realm, use the realm publish
command. Here is an example:
$ realm publish -webservice /testRoot -add testRealm1 -type JNDI
You can also remove a realm using realm publish
with the -remove
option. An example is:
$ realm publish -webservice /testRoot -remove testRealm1
Realm declarations reside in the JNDI namespace. You could deploy a custom realm type that you have written using the -classname
option. Here is an example:
$ realm publish -w /testRoot -add myRealm -classname steve:foo.bar.MyRealm
In this example, the realm name and the class name are the same, but they do not have to be so.
Create a user with the realm user
command. An example is:
$ realm user -webservice /testRoot -realm testRealm1 -add steve -p boss
To create a group use realm group, as follows:
$ realm group -webservice /testRoot -realm testRealm1 -add HRgroup -p gpswd1
With either of these commands, if the password is left blank, the principal name is used for the password.
You can delete a user as follows:
$ realm user -webservice /testRoot -realm testRealm1 -remove steve
To delete a group use the realm group command. An example is:
$ realm group -webservice /testRoot -realm testRealm1 -remove HRgroup
Use the realm user
command to list the users in a realm, as shown in this example:
$ realm user -webservice /testRoot -realm testRealm1
Use realm group to list groups in a realm. For example:
$ realm group -webservice /testRoot -realm testRealm1
Use the parent
variant of the realm
command to add a principal to a group. Here is an example:
$ realm parent -w /testRoot -realm testRealm -group group1 -add user1
Remove a principal from a group also using realm parent
, with the -remove
option, as shown in:
$ realm parent -w /testRoot -realm testRealm -group group1 -remove user1
You can also list principals within a group by using the realm parent
command. For example:
$ realm parent -w /testRoot -realm testRealm -group group1
To query which groups a principal is a member of use the -query
option. For example:
$ realm parent -w /testRoot -realm testRealm -query user1
When you declare realms for a service, they are located in a realms
subcontext of the service. For JNDI-type realms, there are additional subcontexts within the realms
context that contain the realm's principal declarations.
Removing the Web service realms
context removes all realm definitions for the service, such as user and group names, permission mappings, and so on. However any external resources, such as table entries, would still remain. For efficient realm management, it is much better to use the session shell realm commands.
Removing subcontexts of realms can affect JNDI-type realms.
RDBMS-type realms use the following database tables:
JAVA$HTTP$REALM$PRINCIPAL$
-- contains all principals and encoded versions of their passwords
JAVA$HTTP$REALM$GROUP$
-- contains principal/group relationships
Note that creating an RDBMS-type realm also creates a /realms
context in the Web service root, and entries in this context. But no subcontexts are created for RDBMS-type realms.
Realms are containers for principals, groups, and the protection schemes that protect Web resources. OSE HTTP security resource protection is local to the servlet context.
When you need to protect a Web resource, you declare a protection scheme. The syntax for a protection scheme is
<authType>:<realmName> | NONE
So, you specify an authentication method, followed by the name of the realm to which the authentication applies, or no protection (NONE).
There are only two valid authentication methods for the OSE/OJVM, as shown below.
BASIC |
BASE64 encoding, which is very insecure. |
DIGEST |
In the DIGEST scheme, both parties keep the password, and pass encrypted codes. The DIGEST scheme is documented in RFC 2069, at http://www.w3.org/Protocols/rfc2069/rfc2069 |
Form-based and SSL schemes are not supported, though they can be plugged in through namespace entries.
Although DIGEST is far more secure than BASIC, not all browsers support it.
You can also declare resources not to be protected. This is useful when the servlet context root is to be protected. However, when the root is protected, the error pages, being part of the tree, are also protected. Delivering an error page is part of the authentication process. If the error page is protected, cycles develop, and the desired behavior is not observed.
Instead of letting the error page default as part of the tree, explicitly declare the error pages as not being protected. Use a protection scheme of <NONE>. For example:
$ realm map -s /testRoot/contexts/myContext -a /system/* -scheme <NONE> $ realm map -s /testRoot/myService/contexts/myContext -a /* -scheme \
basic:testRealm1
The protected path is local to the servlet context. Internally, that path is normalized, enabling stable, predictable patterns for matching. This may cause the internal representation to differ from the original path used to create the protection scheme. HTTP Security will use the longest, most exact match possible when trying to apply the protection rules.
Here is an example that protects paths to resources with the BASIC protection scheme:
$ realm map -s /testRoot/contexts/myContext -a /doc/index.html -scheme \
basic:testRealm1 $ realm map -s /testRoot/contexts/myContext -a /doc -scheme basic:testRealm2 $ realm map -s /testRoot/contexts/myContext -a /doc/* -scheme basic:testRealm3
When declarations are made, as shown in the previous example, the paths are matched to realms as in the following examples:
/doc/index.html -> testRealm1 /doc/foo -> testRealm3 /doc -> testRealm2 /doc/ -> testRealm2 /doc/index -> testRealm3
You can remove the protection on a path using the realm map
command, as shown here:
$ realm map -s /testRoot/contexts/myContext -r /doc/index.html
To list all protected paths within a servlet context, use the realm map
command as shown here:
$ realm map -s /testRoot/contexts/myContext
You can explicitly declare that a path not be protected. Here is an example:
$ realm map -s /testRoot/contexts/myContext -a /system/* -scheme <NONE>
To list all protected paths within a servlet context, just use realm map and specify only the service root. For example:
$ realm map -s /testRoot/contexts/myContext
The JNDI entry for protection mappings is located in the policy
subcontext of the servlet context. Within the policy subcontext there is an object called httpMapping
. This creates the object responsible for handling the security servlet protection mapping. By default, httpMapping
is used as an index into the JAVA$HTTP$REALM$MAPPING$
database table. The HTTP realm mapping table contains all the mapped paths. Using JNDI entry manipulation you could introduce a customized version of httpMapping
.
Permissions are the most complicated of all HTTP security declarations, because they tie service-scoped entities with servlet context-scoped entities and reside in the servlet context themselves.
To set up a permission declaration, supply the following information:
Given all the pieces that are being tied into one permission declaration, it is easy to see why these are the most complicated declarations.
HTTP security permissions concern only valid HTTP request methods: GET, POST, PUT, DELETE, HEAD, TRACE, OPTIONS.
Declare a granted permission on /foo/index.html
for user1
for GET and POST:
$ realm perm -w /testRoot -realm testRealm1 -s /testRoot/contexts/myContext -n \
user1 -u /foo/index.html + get,post
Declare a denied permission on /foo/*
for user1
for PUT and DELETE:
$ realm perm -w /testRoot -realm testRealm1 -s /testRoot/contexts/myContext -n \
user1 -u /foo/* - put,delete
Clear granted permissions on /foo/index.html
for user1
:
$ realm perm -w /testRoot -realm testRealm1 -s /testRoot/contexts/myContext -n \
user1 -u /foo/index.html +
List all permissions for user1
:
$ realm perm -w /testRoot -realm testRealm1 -s /testRoot/contexts/myContext -n \
user1
In the policy
subcontext of a servlet context, there is a config
object. This entry is used to create the object responsible for all permission declaration checks. The object is used as a key into the permissions table: JAVA$HTTP$REALM$POLICY$.
All HTTP security is declared through JNDI namespace entries. This is also true for the servlet that does the enforcing of security. In the servlet context, if there is a PrivilegedServlet
named httpSecurity
, that servlet is added as the first pre-filter for all requests within that servlet context.
Any customization is allowed as long as the PrivilegedServlet
interface is implemented. The purpose of this servlet is to either:
AccessControlException
during its service(HttpRequest.PrivilegedAccess, HttpRequest, HttpResponse)
if there is a perceived security violation
or
After authentication and authorization have taken place, the servlet must set specific authenticated principal values on the request itself. This is the user information that can be retrieved from the request by any executing servlet.
You can use realm secure
to create a security servlet. For example:
$ realm secure -s /testRoot/contexts/myContext
Removing the security servlet removes all security enforcement in a servlet context. If the entry is missing, the Web server continues execution with no security enforcement.
To remove a security servlet, type:
$ rm /myDomain/contexts/myContext/httpSecurity
There are two security-related examples in the $ORACLE_HOME/demo directory of your distribution. The demos are reproduced here.
This example protects the path /event_log*
with a realm that uses a database table for its source of principals. Note that paths in permission declarations are relative to the servlet context mapping.
This example presupposes that the sample database has already been setup. The prerequisites are:
/HRRoot
/HRRoot/contexts/HRContext
that has a virtual path-mapping of ose
docRealmExample
in the domain
First, make sure that there is a security servlet for the servlet context:
$ realm secure -s /HRRoot/contexts/HRContext
Publish a realm that uses a database table for its users:
$ realm publish -w /HRRoot -add docRealmExample -type rdbms
Create a user in the realm:
$ realm user -w /HRRoot -realm docRealmExample -add alex -p welcome
Create a group in the realm:
$ realm group -w /HRRoot -realm docRealmExample -add docGroup -p welcome
Add "alex" to the docGroup
:
$ realm parent -w /HRRoot -realm docRealmExample -group docGroup -add alex
Allow docGroup
to execute HTTP requests with the GET and POST methods:
$ realm perm -w /HRRoot -realm docRealmExample -s \
/HRRoot/contexts/HRContext -name docGroup -path /event_log + get,post
Protect the resource /event_log:
$ realm map -s /HRRoot/contexts/HRContext -add /event_log -scheme \
Basic:docRealmExample
Now, when a client tries to access /ose/event_log
the browser prompts for a username and password. Be sure to type in the username with the correct capitalization ("alex"). Username/password
is alex/welcome
.
You could also enter username: docGroup
password: welcome
To remove the password protection without removing the realm declaration, execute the following session shell command:
$ realm map -s /HRRoot/contexts/HRContext -remove /event_log
dbUserRealm is a simple example that protects the path /doc*
, and only allows the database user HR
access to it. Note that paths in permission declarations are relative to the servlet context mapping.
This example presupposes that the sample database has already been setup. The prerequisites are:
/HRRoot
/HRRoot/contexts/HRContext
that has a virtual path mapping ose
dbUserExample
in the domain
First, be sure that there is a security servlet for the /HRRoot/contexts/HRContext
servlet context:
$ realm secure -s /HRRoot/contexts/HRContext
Next, publish a realm that uses database users as for its principals:
$ realm publish -w /HRRoot -add dbUserExample -type dbuser
Allow HR to execute HTTP requests with the GET and POST methods:
$ realm perm -w /HRRoot -realm dbUserExample -s \
/HRRoot/contexts/HRContext -name HR -path /http_log + get,post
Protect the resource /http_log
:
$ realm map -s /HRRoot/contexts/HRContext -add /http_log -scheme \
Basic:dbUserExample
Now, when a client tries to access /ose/http_log
for the HR demo server the browser prompts for username and password. Be sure that the letter case matches exactly. In this case, the username is literally "HR", and the password is "hr".
To remove the password protection without removing the realm declaration, execute the following session shell command:
$ realm map -s /HRRoot/contexts/HRContext -remove /http_log
There are several layers of suspected problems to eliminate when debugging HTTP security. This minimal checklist helps you get started trouble shooting.
/doc/index.html
is to be accessible only to user1
in myRealm
, using BASIC authentication, then the following must exist:
myRealm
within the domain.
user1
, with a known password.
/doc/index.html
or some more general path to a protection scheme BASIC:myRealm
within the servlet context.
user1
for /doc/index.html
(or a more general path)
|
Copyright © 1996-2001, Oracle Corporation. All Rights Reserved. |
|