Show Contents Previous Page Next Page
Chapter 10 - C API Reference Guide, Part I / Server Core Routines Authorization and Authentication Routines The last core routines we'll consider are those used for access control, authentication,
and authorization. If you are familiar with the Perl API from Chapter 6,
you'll find no surprises here. These routines are declared in http_core.h unless otherwise
specified: int ap_allow_options (request_rec *r)
The ap_allow_options() call returns a bit mask containing
the contents of the Perl-directory Options directive.
You can logically AND this bit mask with a set of symbolic constants
in order to determine which options are set. For example, the
following code fragment checks whether ExecCGI is active
for the directory containing the currently requested document:
if(!(ap_allow_options(r) & OPT_EXECCGI)) {
ap_log_reason("Options ExecCGI is off in this directory",
$r->filename, r);
return HTTP_FORBIDDEN;
}
The options constants are as follows: Constant | Meaning |
---|
OPT_INDEXES
| The Indexes option is set. | OPT_INCLUDES
| The Includes option is set. | OPT_SYM_
LINKS
| The SymLinks option is set. | OPT_EXECCGI
| The ExecCGI option is set. | OPT_UNSET
| (See the description that follows.) | OPT_
INCNOEXEC
| The IncludeNoExec option is set. | OPT_SYM_
OWNER
| The SymLinksIfOwnerMatch option is set. | OPT_MULTI
| The MultiViews option is set. |
Also available are the constants OPT_NONE , for no
options set (this is defined as zero), and OPT_ALL ,
for all but the MultiViews option set. OPT_UNSET corresponds to a bit that is initially
set to 1 in the options flag but is not otherwise used. If no absolute
assignment to the Options directive has been made, then
this bit will remain set; otherwise, it will be unset. In other
words, you can test this bit to determine whether only additive
and subtractive assignments to Options have been made.
In a directory with this Options directive, the OPT_UNSET
bit will be true:
Options +ExecCGI -Indexes
However, in a directory with this directive, the bit will be false:
Options ExecCGI As Commander Spock would say, "Fascinating."
const char *ap_auth_name (request_rec *r)
If authentication is configured for the currently requested document
or directory, ap_ auth_name() will return the name of the
current authentication realm, as defined by the AuthName
directive. If no realm is currently defined, this function will
return NULL . Note that it is quite possible for the current request to have
an authentication realm without authentication actually being active.
For example, there may be no requires directive in the directory
configuration.
const char *auth_name = ap_auth_name(r);
const char *ap_auth_type (request_rec *r)
This call returns the type of authentication configured for the
current file or directory or NULL if none. The current
possibilities are Basic and Digest.
const char *auth_type = ap_auth_type(r);
if(strcasecmp(auth_type, "basic")) {
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARN, r->server,
"%s can't handle AuthType %s", __FILE__, auth_type);
return DECLINED;
}
Although the information returned by ap_auth_type() seems
redundant with the contents of the connection record's ap_auth_type
field, there is an important difference. ap_auth_type() returns
the authentication scheme configured for the current directory,
whereas the connection record's ap_auth_type field returns
the authentication scheme only if authentication is actually in use.
To determine whether authentication is active, you should only trust
the connection record's field.
int ap_get_basic_auth_pw (request_rec *r, const char **pw)
If the browser provided password authentication in making its request,
the ap_get_basic_ auth_pw() call will return the password.
You pass the function the request record in r and the
address of a character pointer in pw . If successful,
the function will return a result code of OK and place
a copy of the password in pw . Otherwise, the function
will return one of the result codes DECLINED , HTTP_INTERNAL_SERVER_ERROR ,
or HTTP_ UNAUTHORIZED . DECLINED is returned
when the current request isn't for a directory that is protected by
Basic authentication. HTTP_INTERNAL_SERVER_ERROR can
occur when the authorization realm directive is missing. Finally,
HTTP_ UNAUTHORIZED is returned if the browser fails to
provide a password or attempts to use the wrong authentication scheme.
This call is typically used by authentication handlers to recover
the user's password. The username can be retrieved from the connection
record's user field. You should then do something with
the two values to validate them.
const char *sent_pw = NULL;
char *user;
int ret = ap_get_basic_auth_pw(r, &sent_pw);
if(ret != OK) {
return ret;
}
user = r->connection->user;
...
void ap_note_basic_auth_failure (request_rec *r)
void ap_note_digest_auth_failure (request_rec *r)
void ap_note_auth_failure (request_rec *r)
(Declared in the header file http_protocol.h .) If
authentication is required for the current directory, but the browser
did not provide the required information, these three variants set
the HTTP authentication gears in motion by sending an "Authentication
Required" message to the browser. ap_note_basic_auth_failure() and ap_note_digest_auth_failure()
are used for Basic and Digest authentication schemes, respectively.
The generic ap_note_auth_failure() call will dispatch to
one of those two routines based on which type of authentication the
current directory is configured to use. We can now write the skeleton for username/password authentication. In this
example, check_auth() is some routine that you provide to check that
the login name and password are valid. Replace this routine with a function
that always returns 1, and you have our Apache::AuthAny module from
Chapter 6!
const char *sent_pw = NULL;
char *user = r->connection->user;
int ret = ap_get_basic_auth_pw(r, &sent_pw);
if (ret != OK) {
return ret;
}
if(!(user && sent_pwd && check_auth(user, sent_pw)) {
ap_note_basic_auth_failure(r);
ap_log_reason("User did not authenticate", r->uri, r);
return HTTP_UNAUTHORIZED;
}
const array_header *ap_requires (request_rec *r)
As we described in Chapter 6, after a successful
authentication, Apache calls the authorization handler to determine whether
the authenticated user is allowed access to the requested document. To do
this, the authorization handler needs to process any and all requires
directives in the current directory configuration. The ap_requires()
call returns the contents of these directives in predigested form. The function result of ap_requires() is an array_header*
containing a list of require_line structs. The definition
of this data type, as found in http_core.h , is as
follows:
typedef struct {
int method_mask;
char *requirement;
} require_line;
method_mask is an integer bitmask constructed from the request
methods listed in the current <Limit> directive, or -1 if no
<Limit> section applies. The set bit numbers correspond to the
method numbers M_GET , M_POST , and so on. For example,
you could determine whether the first requirement applies to POST requests with
the following code fragment:
int isPost = 0 != (requirement[0].method_mask & (1 << M_POST));
requirement is a character string containing the exact text
of the requires directive. You will need to parse this text in
order to determine what type of requirement to apply. Example 10-6 gives a short example of iterating
over the ap_requires() array and printing out the information it contains.
You should be able to use this code in a real authorization module by replacing
the various print statements with code that performs the actual authorization
checks. For real-life examples, see mod_auth, mod_auth_dbm,
and the other standard authorization modules.
Example 10-6. Processing requires
Directives
static char *request_methods[] = {
"GET","PUT","POST","DELETE","CONNECT","OPTIONS","TRACE",NULL
};
#define comma_or_newline(value) \
if(value) fprintf(stderr, ", "); \
else fprintf(stderr, "\n");
static void hello_util_requires_dump(request_rec *r)
{
const array_header *requires = ap_requires(r);
require_line *rq;
int x;
if (!requires) {
fprintf(stderr,
"requires: there are no requirements for this request\n"); return;
}
rq = (require_line *) requires->elts;
for (x = 0; x < requires->nelts; x++) {
const char *line, *requirement;
int i;
fprintf(stderr, "requires: limited to request methods: ");
for(i=0; request_methods[i]; i++) {
if (rq[x].method_mask & (1 << i))
fprintf(stderr, "%s ", request_methods[i]);
}
fprintf(stderr, "\n");
line = rq[x].requirement;
requirement = ap_getword(r->pool, &line, ' ');
if (!strcmp(requirement, "valid-user")) {
fprintf(stderr, "requires: any valid-user allowed here.\n");
return;
}
if (!strcmp(requirement, "user")) {
fprintf(stderr, "requires: allowed users: ");
while (line[0]) {
requirement = ap_getword_conf(r->pool, &line);
fprintf(stderr, "`%s'", requirement);
comma_or_newline(line[0]);
}
}
else if (!strcmp(requirement, "group")) {
fprintf(stderr, "requires: allowed groups: ");
while (line[0]) {
requirement = ap_getword_conf(r->pool, &line);
fprintf(stderr, "`%s'", requirement);
comma_or_newline(line[0]);
}
}
}
}
int ap_satisfies (request_rec *r)
The Satisfy directive determines whether a request for a URI
that is protected by both access control and authentication must pass through
both phases successfully or either one or the other. If Satisfy
is set to all, all access control and authentication tests must
be passed successfully. In contrast, if the directive is set to any,
then the request will be allowed if any of the checks returns OK .
Handlers involved with access control can gain access to this configuration
directive using the ap_satisfies() function. It returns one of the
constants SATISFY_ANY , SATISFY_ALL , or SATISFY_NOSPEC .
The last constant indicates that the directive wasn't present at all. Each
of these constants, and the declaration of ap_satisfies() itself,
is found in http_core.h.
As an example, consider an access control handler that wants to write an error log message
when a user is denied access, but not when SATISFY_ANY is set, because the user
might still be allowed in during the authentication phase. It can do the following:
if (return_value == HTTP_FORBIDDEN) {
if (!(r->satisfies == SATISFY_ANY && ap_some_auth_required(r)))
ap_log_reason("Client denied by server configuration", r->uri, r);
}
return return_value;
int ap_some_auth_required (request_rec *r)
The ap_some_auth_required() function can be used within any handler to determine
whether authentication is required for the requested document. If you are writing a
module that must always run with authentication enabled (such as a password changing
program), you can use this call to make sure that the module is never inadvertently run
without protection. For example:
if(!ap_some_auth_required(r)) {
ap_log_reason("I won't go further unless the user is authenticated",
r->uri, r);
return HTTP_FORBIDDEN;
}
The next chapter shows you how to create configuration directives with
the C API and covers less frequently used parts of the C-language API. Footnotes 4 When native syslog support is enabled,
the stderr stream will be redirected to /dev/null !
5 In fact, the error log API maps directly to
syslog when native syslog support is enabled. See the Apache
documentation on the ErrorLog directive for details on enabling native
syslog support. 6 Reliable piped log support was not available on
Win32 platforms at the time this was written.
Show Contents Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |