mod_authn_webid/0000775004264400426440000000000011533313561013553 5ustar oshanioshanimod_authn_webid/configure.in0000664004264400426440000000176111522060166016067 0ustar oshanioshaniAC_INIT(WebID FOAF+SSL authentication module for Apache 2, 1.0, presbrey@csail.mit.edu, mod_authn_webid) AC_PREREQ(2.57) AC_CONFIG_SRCDIR(mod_authn_webid.c) AC_REVISION($Revision: 26165 $) AC_PROG_CC AC_PROG_CC_C_O AC_PATH_PROGS(PKG_CONFIG, pkg-config) if test -z "$PKG_CONFIG"; then AC_MSG_ERROR([cannot locate pkg-config]) fi if ! $PKG_CONFIG libcrypto --exists; then AC_MSG_ERROR([cannot locate OpenSSL Toolkit]) fi if ! $PKG_CONFIG redland --exists; then AC_MSG_ERROR([cannot locate Redland RDF Library - see http://librdf.org/]) fi AC_ARG_WITH(apache, AC_HELP_STRING([--with-apache=DIR],[use Apache in DIR]), [with_apache="$withval:$PATH"], [with_apache="$PATH"]) AC_PATH_PROGS([APXS], [apxs apxs2], [], [$with_apache]) if test -z "$APXS"; then AC_MSG_ERROR([cannot locate Apache apxs]) fi PKG_CFLAGS="`$PKG_CONFIG --cflags libcrypto redland`" PKG_LIBS="`$PKG_CONFIG --libs libcrypto redland`" AC_SUBST(PKG_CFLAGS) AC_SUBST(PKG_LIBS) AC_CONFIG_FILES([Makefile]) AC_OUTPUT mod_authn_webid/README.html0000664004264400426440000000550511522060166015401 0ustar oshanioshani

WebID FOAF+SSL authentication module for Apache 2

The latest version of this module can be found at:

Visit the W3 ESW wiki for more information about FOAF+SSL:

Requirements

Release versions of the following packages for your Linux distribution:

Development versions of the following packages for your Linux distribution:

Installing

Use the following compilation and installation procedure:

$ autoconf
$ ./configure
$ sudo make install

The 'make install' command calls Apache's apxs utility to create and install the mod_authn_webid DSO using default Apache module installation parameters.

Configuration Directives

AuthWebIDAuthoritative
Set to 'Off' to allow access control to be passed along to lower modules if the WebID is not known to this module

Sample httpd.conf

LoadModule authn_webid_module modules/mod_authn_webid.so

SSLVerifyClient optional_no_ca

# WebID ignored
<Location />
</Location>

# WebID optional
<Location /public/>
    AuthType WebID
    Require everyone
    AuthWebIDAuthoritative off
</Location>

# WebID required
<Location /private/>
    AuthType WebID
    Require valid-user
</Location>

Authentication Details

Clients are verified using the following SPARQL query:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX cert: <http://www.w3.org/ns/auth/cert#>
PREFIX rsa: <http://www.w3.org/ns/auth/rsa#>
SELECT ?m ?e ?mod ?exp WHERE {
    ?key cert:identity <%s>;
         rsa:modulus ?m;
         rsa:public_exponent ?e.
    OPTIONAL { ?m cert:hex ?mod . }
    OPTIONAL { ?e cert:decimal ?exp. }
}

%s is substituted by the client's WebID claim.

Matching modulus and exponent triggers successful authentication. Only hex characters [0-9a-f] are considered for modulus comparison.

The optional clauses maintain compatibility for users with FOAF WebIDs before the changes to the cert datatypes discussed on foaf-protocols here: http://lists.foaf-project.org/pipermail/foaf-protocols/2010-March/001857.html

Support

Please visit the issue tracker for bug reports, feature requests, and other support.

Author

Joe Presbrey
presbrey@csail.mit.edu

$Id: README 28777 2010-04-12 20:49:23Z presbrey $ mod_authn_webid/Makefile.in0000664004264400426440000000041111522060166015612 0ustar oshanioshaniall: @APXS@ -c @PKG_CFLAGS@ @PKG_LIBS@ mod_authn_webid.c install: @APXS@ -c -i @PKG_CFLAGS@ @PKG_LIBS@ mod_authn_webid.c clean: rm -f mod_authn_webid.{la,lo,slo,o} -r .libs distclean: clean rm -f config.log config.status configure Makefile -r autom4te.cache mod_authn_webid/Download0000775004264400426440000000042011522060166015242 0ustar oshanioshani SetHandler php5-script mod_authn_webid/LICENSE0000644€Í00426440000000206611533313561013333 0ustar oshaniCopyright (C) 2010 by Joe Presbrey Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mod_authn_webid/mod_authn_webid.c0000664004264400426440000003604511522060166017055 0ustar oshanioshani/* mod_authn_webid * WebID FOAF+SSL authentication module for Apache 2 * * Joe Presbrey * * $Id: mod_authn_webid.c 29767 2010-10-26 01:09:58Z presbrey $ */ #include "apr_strings.h" #define APR_WANT_STRFUNC #include "apr_want.h" #include "ap_config.h" #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_request.h" #include "mod_auth.h" #include "mod_ssl.h" #include "openssl/ssl.h" #include "redland.h" #define UD_WEBID_KEY "mod_authn_webid:client_WebID" #define UD_TTL_KEY "mod_authn_webid:client_TTL" #define SPARQL_WEBID \ "PREFIX rdf: " \ "PREFIX cert: " \ "PREFIX rsa: " \ "SELECT ?m ?e ?mod ?exp WHERE {" \ " ?key cert:identity <%s>; rsa:modulus ?m; rsa:public_exponent ?e." \ " OPTIONAL { ?m cert:hex ?mod. }" \ " OPTIONAL { ?e cert:decimal ?exp. }" \ "}" static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *ssl_var_lookup; // 2010-09-28 tested against httpd-trunk r1002363 #if AP_MODULE_MAGIC_AT_LEAST(20060101,0) static APR_OPTIONAL_FN_TYPE(ssl_ext_list) *ssl_ext_list; #else static APR_OPTIONAL_FN_TYPE(ssl_ext_lookup) *ssl_ext_lookup; #endif typedef struct { int authoritative; } authn_webid_config_rec; static void * create_authn_webid_dir_config(apr_pool_t *p, char *dirspec) { authn_webid_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); conf->authoritative = -1; return conf; } static void * merge_authn_webid_dir_config(apr_pool_t *p, void *parent_conf, void *newloc_conf) { authn_webid_config_rec *pconf = parent_conf, *nconf = newloc_conf, *conf = apr_pcalloc(p, sizeof(*conf)); conf->authoritative = (nconf->authoritative != -1) ? nconf->authoritative : pconf->authoritative; return conf; } static const command_rec authn_webid_cmds[] = { AP_INIT_FLAG("AuthWebIDAuthoritative", ap_set_flag_slot, (void *)APR_OFFSETOF(authn_webid_config_rec, authoritative), OR_AUTHCFG, "Set to 'Off' to allow access control to be passed along to " "lower modules if the WebID is not known to this module"), {NULL} }; module AP_MODULE_DECLARE_DATA authn_webid_module; static int hex_or_x(int c) { if (c >= '0' && c <= '9') return c; c |= 32; if (c >= 'a' && c <= 'f') return c; return 'x'; } static int matches_pkey(unsigned char *s, char *pkey) { if (s == NULL || pkey == NULL) return 0; unsigned int s_s = strlen((const char*)s); unsigned int s_pkey = strlen(pkey); unsigned int fc, pc, j, k = 0; for (j = 0; j < s_s; j++) { if ((fc = hex_or_x(s[j])) == 'x') continue; pc = hex_or_x(pkey[k]); if (fc != pc) break; k++; } if (k == s_pkey) return 1; return 0; } static int validate_webid(request_rec *request, const char *subjAltName, char *pkey_n, unsigned int pkey_e_i) { int r = HTTP_UNAUTHORIZED; librdf_world *rdf_world = NULL; librdf_storage *rdf_storage = NULL; librdf_model *rdf_model = NULL; librdf_query *rdf_query = NULL; librdf_query_results *rdf_query_results = NULL; rdf_world = librdf_new_world(); if (rdf_world != NULL) { librdf_world_open(rdf_world); rdf_storage = librdf_new_storage(rdf_world, "uri", subjAltName, NULL); if (rdf_storage != NULL) { rdf_model = librdf_new_model(rdf_world, rdf_storage, NULL); } else ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, request, "WebID: librdf_new_storage returned NULL"); } if (rdf_model != NULL) { char *c_query = apr_psprintf(request->pool, SPARQL_WEBID, subjAltName); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "WebID: SPARQL query = %s", c_query); rdf_query = librdf_new_query(rdf_world, "sparql", NULL, (unsigned char*)c_query, NULL); } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, request, "WebID: librdf_new_query returned NULL"); } if (rdf_query != NULL) { rdf_query_results = librdf_query_execute(rdf_query, rdf_model); if (rdf_query_results != NULL) { for (; r != OK && librdf_query_results_finished(rdf_query_results)==0; librdf_query_results_next(rdf_query_results)) { librdf_node *m_node, *e_node; unsigned char *rdf_mod; unsigned char *rdf_exp; if (r != OK && NULL != (m_node = librdf_query_results_get_binding_value_by_name(rdf_query_results, "m")) && NULL != (e_node = librdf_query_results_get_binding_value_by_name(rdf_query_results, "e"))) { if (librdf_node_get_type(m_node) != LIBRDF_NODE_TYPE_LITERAL) { librdf_free_node(m_node); m_node = librdf_query_results_get_binding_value_by_name(rdf_query_results, "mod"); } if (librdf_node_get_type(e_node) != LIBRDF_NODE_TYPE_LITERAL) { librdf_free_node(e_node); e_node = librdf_query_results_get_binding_value_by_name(rdf_query_results, "exp"); } if (librdf_node_get_type(m_node) == LIBRDF_NODE_TYPE_LITERAL && librdf_node_get_type(e_node) == LIBRDF_NODE_TYPE_LITERAL) { rdf_mod = librdf_node_get_literal_value(m_node); rdf_exp = librdf_node_get_literal_value(e_node); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "WebID: modulus = %s", rdf_mod); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "WebID: exponent = %s", rdf_exp); if (rdf_exp != NULL && apr_strtoi64((char*)rdf_exp, NULL, 10) == pkey_e_i && matches_pkey(rdf_mod, pkey_n)) r = OK; librdf_free_node(m_node); librdf_free_node(e_node); } } } librdf_free_query_results(rdf_query_results); } else ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, request, "WebID: librdf_query_execute returned NULL"); librdf_free_query(rdf_query); } else ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, request, "WebID: librdf_new_query returned NULL"); if (rdf_model) librdf_free_model(rdf_model); if (rdf_storage) librdf_free_storage(rdf_storage); if (rdf_world) librdf_free_world(rdf_world); return r; } char * get_list_item(apr_pool_t *p, const char **field) { const char *tok_start; const unsigned char *ptr; unsigned char *pos; char *token; int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0; if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) { return NULL; } token = apr_palloc(p, tok_len + 1); for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token; *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); ++ptr) { if (in_qpair) { in_qpair = 0; *pos++ = *ptr; } else { switch (*ptr) { case '\\': in_qpair = 1; if (addspace == 1) *pos++ = ' '; *pos++ = *ptr; addspace = 0; break; case '"' : if (!in_com) in_qstr = !in_qstr; if (addspace == 1) *pos++ = ' '; *pos++ = *ptr; addspace = 0; break; case '(' : if (!in_qstr) ++in_com; if (addspace == 1) *pos++ = ' '; *pos++ = *ptr; addspace = 0; break; case ')' : if (in_com) --in_com; *pos++ = *ptr; addspace = 0; break; case ' ' : case '\t': if (addspace) break; if (in_com || in_qstr) *pos++ = *ptr; else addspace = 1; break; case '=' : case '/' : case ';' : if (!(in_com || in_qstr)) addspace = -1; *pos++ = *ptr; break; default : if (addspace == 1) *pos++ = ' '; *pos++ = *ptr; addspace = 0; break; } } } *pos = '\0'; return token; } static int authenticate_webid_user(request_rec *request) { int r = 0; authn_webid_config_rec *conf = ap_get_module_config(request->per_dir_config, &authn_webid_module); if (!conf->authoritative) r = DECLINED; else r = HTTP_UNAUTHORIZED; /* Check for AuthType WebID */ const char *current_auth = ap_auth_type(request); if (!current_auth || strcasecmp(current_auth, "WebID") != 0) { return DECLINED; } request->ap_auth_type = "WebID"; /* Check for WebID cached in SSL session */ const char *subjAltName = NULL; { void *data = NULL; if (apr_pool_userdata_get(&data, UD_WEBID_KEY, request->connection->pool) == APR_SUCCESS && data != NULL) { subjAltName = data; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "get connection cached WebID: %s (%d)", subjAltName, subjAltName==NULL?0:(int)strlen(subjAltName)); if (strlen(subjAltName)) { request->user = (char *)subjAltName; r = OK; } return r; } } #if AP_MODULE_MAGIC_AT_LEAST(20060101,0) apr_array_header_t *subjAltName_list = ssl_ext_list(request->pool, request->connection, 1, "2.5.29.17"); #else subjAltName = ssl_ext_lookup(request->pool, request->connection, 1, "2.5.29.17"); #endif /* Load X509 Public Key + Exponent */ char *pkey_n = NULL; char *pkey_e = NULL; unsigned int pkey_e_i = 0; #if AP_MODULE_MAGIC_AT_LEAST(20060101,0) if (subjAltName_list != NULL) { #else if (subjAltName != NULL) { #endif char *c_cert = NULL; BIO *bio_cert = NULL; X509 *x509 = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; BIO *bio = NULL; BUF_MEM *bptr = NULL; if (NULL != (c_cert = ssl_var_lookup(request->pool, request->server, request->connection, request, "SSL_CLIENT_CERT")) && NULL != (bio_cert = BIO_new_mem_buf(c_cert, strlen(c_cert))) && NULL != (x509 = PEM_read_bio_X509(bio_cert, NULL, NULL, NULL)) && NULL != (pkey = X509_get_pubkey(x509)) && NULL != (rsa = EVP_PKEY_get1_RSA(pkey))) { // public key modulus bio = BIO_new(BIO_s_mem()); BN_print(bio, rsa->n); BIO_get_mem_ptr(bio, &bptr); pkey_n = apr_pstrndup(request->pool, bptr->data, bptr->length); BIO_free(bio); // public key exponent bio = BIO_new(BIO_s_mem()); BN_print(bio, rsa->e); BIO_get_mem_ptr(bio, &bptr); pkey_e = apr_pstrndup(request->pool, bptr->data, bptr->length); pkey_e_i = apr_strtoi64(pkey_e, NULL, 16); BIO_free(bio); } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, request, "WebID: invalid client certificate"); } if (rsa) RSA_free(rsa); if (pkey) EVP_PKEY_free(pkey); if (x509) X509_free(x509); if (bio_cert) BIO_free(bio_cert); } if (pkey_n != NULL && pkey_e != NULL) { #if AP_MODULE_MAGIC_AT_LEAST(20060101,0) const char *san; char *tok; int i; for (i = 0; i < subjAltName_list->nelts; i++) { san = APR_ARRAY_IDX(subjAltName_list, i, const char*); while ((tok = get_list_item(request->pool, &san)) != NULL) { if (strncmp(tok, "URI:", 4) == 0) { if (validate_webid(request, tok+4, pkey_n, pkey_e_i) == OK) { subjAltName = tok+4; r = OK; break; } } } } #else ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "WebID: subjectAltName = %s", subjAltName); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "WebID: client pkey.n = %s", pkey_n); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "WebID: client pkey.e = %d (%s)", pkey_e_i, pkey_e); const char *san = subjAltName; char *tok; while ((tok = get_list_item(request->pool, &san)) != NULL) { if (strncmp(tok, "URI:", 4) == 0) { if (validate_webid(request, tok+4, pkey_n, pkey_e_i) == OK) { subjAltName = tok+4; r = OK; break; } } } #endif } if (r == OK) { ap_log_rerror(APLOG_MARK, APLOG_INFO | APLOG_TOCLIENT, 0, request, "WebID authentication (%sauthoritative) succeeded SAN: <%s> URI: <%s> Pubkey: \"%s\"", conf->authoritative?"":"non-", subjAltName, request->uri, pkey_n); request->user = apr_psprintf(request->connection->pool, "%s", subjAltName); } else { ap_log_rerror(APLOG_MARK, APLOG_WARNING | APLOG_TOCLIENT, 0, request, "WebID authentication (%sauthoritative) failed SANs: \"%s\" URI: <%s> Pubkey: \"%s\"", conf->authoritative?"":"non-", subjAltName, request->uri, pkey_n); subjAltName = ""; } ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, request, "set connection cached WebID: %s", subjAltName); apr_pool_userdata_set(apr_pstrdup(request->connection->pool, subjAltName), UD_WEBID_KEY, NULL, request->connection->pool); return r; } static void import_ssl_func() { ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); #if AP_MODULE_MAGIC_AT_LEAST(20060101,0) ssl_ext_list = APR_RETRIEVE_OPTIONAL_FN(ssl_ext_list); #else ssl_ext_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_ext_lookup); #endif } static void register_hooks(apr_pool_t *p) { #if AP_MODULE_MAGIC_AT_LEAST(20080403,1) ap_hook_check_authn(authenticate_webid_user, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_URI); #else ap_hook_check_user_id(authenticate_webid_user, NULL, NULL, APR_HOOK_MIDDLE); #endif ap_hook_optional_fn_retrieve(import_ssl_func, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA authn_webid_module = { STANDARD20_MODULE_STUFF, create_authn_webid_dir_config, merge_authn_webid_dir_config, NULL, NULL, authn_webid_cmds, register_hooks };