summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Pazdziora <jpazdziora@redhat.com>2016-05-28 08:31:32 +0200
committerSimo Sorce <simo@redhat.com>2016-06-09 10:11:43 -0400
commitd1710aff7c72263f691f09f20f91922a3ce57cfc (patch)
tree4840aa7bba096593a3470097b44c6f066664d37c
parent17c292a0b4f7ce7c08780c17c1300721c3256031 (diff)
downloadmod_auth_gssapi-d1710aff7c72263f691f09f20f91922a3ce57cfc.tar.gz
mod_auth_gssapi-d1710aff7c72263f691f09f20f91922a3ce57cfc.tar.xz
mod_auth_gssapi-d1710aff7c72263f691f09f20f91922a3ce57cfc.zip
Add support for GssapiImpersonate.
This is can be enabled on locations that are authenticated by another module to obtain a ticket for the user, so that the application gets access to krb5 credentials and all named attributes for the client. The service needs to be authorized by the KDC if there is the need to use credentials for further ticket acquisition by setting the ok_to_auth_as_delegate flag on the service principal. This will provide a forwardable ticket that can be used to obtain additional tickets via consrained delegation (also subkect to KDC access control). Signed-off-by: Jan Pazdziora <jpazdziora@redhat.com> Signed-off-by: Simo Sorce <simo@redhat.com> Close #92
-rw-r--r--README16
-rw-r--r--src/mod_auth_gssapi.c157
-rw-r--r--src/mod_auth_gssapi.h1
3 files changed, 173 insertions, 1 deletions
diff --git a/README b/README
index 1c5d1cd..755015e 100644
--- a/README
+++ b/README
@@ -310,3 +310,19 @@ Auth mechanism. Enable GssapiNegotiateOnce to avoid this situation.
- **Enable with:** GssapiNegotiateOnce On
- **Default:** GssapiNegotiateOnce Off
+### GssapiImpersonate
+
+This option can be used even if AuthType GSSAPI is not used for given
+Location or LocationMatch, to obtain service ticket for a user that was
+already authenticated by different module.
+
+The principal of the user is retrieved from the internal r->user
+identifier which typically holds the username from the authentication
+results.
+
+Make sure the server principal is set to allow to acquire forwardable
+tickets to itself from arbitrary users, for use with constrained
+delegation, for example with the option +ok_to_auth_as_delegate.
+
+- **Enable with:** GssapiImpersonate On
+- **Default:** GssapiImpersonate Off
diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c
index 97d875e..0785a26 100644
--- a/src/mod_auth_gssapi.c
+++ b/src/mod_auth_gssapi.c
@@ -289,10 +289,12 @@ static bool is_mech_allowed(gss_OID_set allowed_mechs, gss_const_OID mech,
#define AUTH_TYPE_NEGOTIATE 0
#define AUTH_TYPE_BASIC 1
#define AUTH_TYPE_RAW_NTLM 2
+#define AUTH_TYPE_IMPERSONATE 3
const char *auth_types[] = {
"Negotiate",
"Basic",
"NTLM",
+ "Impersonate",
NULL
};
@@ -618,12 +620,158 @@ static bool use_s4u2proxy(struct mag_req_cfg *req_cfg) {
}
return false;
}
-#endif
static int mag_complete(struct mag_req_cfg *req_cfg, struct mag_conn *mc,
gss_name_t client, gss_OID mech_type,
uint32_t vtime, gss_cred_id_t delegated_cred);
+static apr_status_t mag_s4u2self(request_rec *req)
+{
+ apr_status_t ret = DECLINED;
+ const char *type;
+ struct mag_config *cfg;
+ struct mag_req_cfg *req_cfg;
+ gss_OID mech_type = discard_const(gss_mech_krb5);
+ gss_OID_set_desc gss_mech_krb5_set = { 1, mech_type };
+ gss_buffer_desc user_name = GSS_C_EMPTY_BUFFER;
+ gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL;
+ gss_name_t user = GSS_C_NO_NAME;
+ gss_name_t client = GSS_C_NO_NAME;
+ gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
+ gss_name_t server_name = GSS_C_NO_NAME;
+ gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
+ gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+ gss_buffer_desc init_token = GSS_C_EMPTY_BUFFER;
+ gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
+ gss_buffer_desc accept_token = GSS_C_EMPTY_BUFFER;
+ struct mag_conn *mc = NULL;
+ uint32_t maj, min;
+
+ req_cfg = mag_init_cfg(req);
+ cfg = req_cfg->cfg;
+
+ if (!cfg->s4u2self) {
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
+ "GSSapiImpersonate not On, skipping impersonation.");
+ return DECLINED;
+ }
+
+ type = ap_auth_type(req);
+ if (type && (strcasecmp(type, "GSSAPI") == 0)) {
+ /* do not try to impersonate if GSSAPI is handling real auth */
+ return DECLINED;
+ }
+
+ if (!req->user) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
+ "Authentication user not found, "
+ "skipping impersonation.");
+ return DECLINED;
+ }
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
+ "Using user %s for impersonation.", req->user);
+
+ if (!mag_acquire_creds(req, cfg, &gss_mech_krb5_set,
+ GSS_C_BOTH, &server_cred, NULL)) {
+ goto done;
+ }
+
+ maj = gss_inquire_cred(&min, server_cred, &server_name, NULL, NULL, NULL);
+ if (GSS_ERROR(maj)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
+ "Failed to inquire server's creds: %s",
+ mag_error(req, "gss_inquired_cred()",
+ maj, min));
+ goto done;
+ }
+
+ user_name.value = req->user;
+ user_name.length = strlen(user_name.value);
+ maj = gss_import_name(&min, &user_name, GSS_C_NT_USER_NAME, &user);
+ if (GSS_ERROR(maj)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
+ "Failed to import user's name: %s",
+ mag_error(req, "gss_import_name()",
+ maj, min));
+ goto done;
+ }
+
+ maj = gss_acquire_cred_impersonate_name(&min, server_cred, user,
+ GSS_C_INDEFINITE,
+ &gss_mech_krb5_set,
+ GSS_C_INITIATE, &user_cred,
+ NULL, NULL);
+ if (GSS_ERROR(maj)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
+ "Failed to impersonate %s: %s", req->user,
+ mag_error(req, "gss_acquire_cred_impersonate_name()",
+ maj, min));
+ goto done;
+ }
+
+ /* the following exchange is needed to decrypt the ticket and get named
+ * attributes as well as check if the ticket is forwardable when
+ * delegated credentials are requested */
+ do {
+ /* output and input are inverted here, this is intentional */
+
+ /* now acquire credentials for impersonated user to self */
+ maj = gss_init_sec_context(&min, user_cred, &initiator_context,
+ server_name, discard_const(gss_mech_krb5),
+ GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+ GSS_C_INDEFINITE,
+ GSS_C_NO_CHANNEL_BINDINGS, &accept_token,
+ NULL, &init_token, NULL, NULL);
+ if (GSS_ERROR(maj)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
+ mag_error(req, "gss_init_sec_context()", maj, min));
+ goto done;
+ }
+ gss_release_buffer(&min, &accept_token);
+
+ /* accept context to be able to store delegated credentials */
+ maj = gss_accept_sec_context(&min, &acceptor_context, server_cred,
+ &init_token, GSS_C_NO_CHANNEL_BINDINGS,
+ &client, NULL, &accept_token,
+ NULL, NULL, &delegated_cred);
+ if (GSS_ERROR(maj)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
+ mag_error(req, "gss_accept_sec_context()",
+ maj, min));
+ goto done;
+ }
+ gss_release_buffer(&min, &init_token);
+ } while (maj == GSS_S_CONTINUE_NEEDED);
+
+ if (cfg->deleg_ccache_dir && delegated_cred == GSS_C_NO_CREDENTIAL) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
+ "Failed to obtain delegated credentials, "
+ "does service have +ok_to_auth_as_delegate?");
+ goto done;
+ }
+
+ mc = mag_new_conn_ctx(req->pool);
+ mc->auth_type = AUTH_TYPE_IMPERSONATE;
+
+ ret = mag_complete(req_cfg, mc, client, mech_type, GSS_C_INDEFINITE, delegated_cred);
+ if (ret != OK) ret = DECLINED;
+
+done:
+ gss_release_cred(&min, &user_cred);
+ gss_release_name(&min, &user);
+ gss_release_name(&min, &client);
+ gss_release_cred(&min, &server_cred);
+ gss_release_name(&min, &server_name);
+ gss_release_cred(&min, &delegated_cred);
+ gss_delete_sec_context(&min, &initiator_context, GSS_C_NO_BUFFER);
+ gss_release_buffer(&min, &init_token);
+ gss_delete_sec_context(&min, &acceptor_context, GSS_C_NO_BUFFER);
+ gss_release_buffer(&min, &accept_token);
+ return ret;
+}
+#endif
+
static int mag_auth(request_rec *req)
{
const char *type;
@@ -1391,6 +1539,10 @@ static const command_rec mag_commands[] = {
OR_AUTHCFG, "Directory to store delegated credentials"),
AP_INIT_FLAG("GssapiDelegCcacheUnique", mag_deleg_ccache_unique, NULL,
OR_AUTHCFG, "Use unique ccaches for delgation"),
+ AP_INIT_FLAG("GssapiImpersonate", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(struct mag_config, s4u2self), OR_AUTHCFG,
+ "Do impersonation call (S4U2Self) "
+ "based on already authentication username"),
#endif
#ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
@@ -1418,6 +1570,9 @@ mag_register_hooks(apr_pool_t *p)
#endif
ap_hook_post_config(mag_post_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
+#ifdef HAVE_CRED_STORE
+ ap_hook_fixups(mag_s4u2self, NULL, NULL, APR_HOOK_MIDDLE);
+#endif
}
module AP_MODULE_DECLARE_DATA auth_gssapi_module =
diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h
index 0c77b8b..6ff9fbd 100644
--- a/src/mod_auth_gssapi.h
+++ b/src/mod_auth_gssapi.h
@@ -71,6 +71,7 @@ struct mag_config {
char *deleg_ccache_dir;
gss_key_value_set_desc *cred_store;
bool deleg_ccache_unique;;
+ bool s4u2self;
#endif
struct seal_key *mag_skey;