HTTPCode HTTPDigestAuthenticate::check_auth_header(std::string authorization_header,
                                                   bool& auth_info,
                                                   Response* response)
{
  HTTPCode rc = HTTP_OK;

  if (authorization_header == "")
  {
    // No authorization information present. Default the private ID from the pub
    // public ID
    TRC_DEBUG("No authorization header present");

    auth_info = false;

    std::string sip = "sip:";
    size_t sip_pos = _impu.find(sip);
    if (sip_pos != std::string::npos)
    {
      _impi = _impu.substr(sip_pos + sip.length(), std::string::npos);
    }
    else
    {
      TRC_DEBUG("Private ID can't be derived from the public ID (%s)", _impu.c_str());
      rc = HTTP_BAD_REQUEST;
    }
  }
  else
  {
    // Check header is valid. Header should contain a username, realm, nonce, uri,
    // qop, nc, cnonce, response, opaque or only a username.
    TRC_DEBUG("Authorization header present: %s", authorization_header.c_str());

    rc = parse_auth_header(authorization_header, auth_info, response);

    if (rc == HTTP_OK)
    {
      if (auth_info)
      {
        if (response->_qop != "auth")
        {
          TRC_DEBUG("Client requesting non-auth (%s) digest", response->_qop.c_str());
          return HTTP_BAD_REQUEST;
        }
      }

      TRC_DEBUG("Authorization header is in a valid form for ID %s", _impi.c_str());
    }
  }

  return rc;
}
Esempio n. 2
0
// Authorize against the opened passwords file. Return 1 if authorized.
static int authorize(struct mg_connection *conn, FILE *fp) {
  struct ah ah;
  char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN];

  if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
    return 0;
  }

  // Loop over passwords file
  while (fgets(line, sizeof(line), fp) != NULL) {
    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
      continue;
    }

    if (!strcmp(ah.user, f_user) &&
        !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
      return check_password(conn->request_info.request_method, ha1, ah.uri,
                            ah.nonce, ah.nc, ah.cnonce, ah.qop, ah.response);
  }

  return 0;
}
Esempio n. 3
0
static int mag_auth(request_rec *req)
{
    const char *type;
    int auth_type = -1;
    struct mag_req_cfg *req_cfg;
    struct mag_config *cfg;
    const char *auth_header;
    char *auth_header_type;
    int ret = HTTP_UNAUTHORIZED;
    gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
    gss_ctx_id_t *pctx;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc name = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc ba_user;
    gss_buffer_desc ba_pwd;
    gss_name_t client = GSS_C_NO_NAME;
    gss_cred_id_t acquired_cred = GSS_C_NO_CREDENTIAL;
    gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
    gss_cred_usage_t cred_usage = GSS_C_ACCEPT;
    uint32_t vtime;
    uint32_t maj, min;
    char *reply;
    size_t replen;
    gss_OID mech_type = GSS_C_NO_OID;
    gss_OID_set desired_mechs = GSS_C_NO_OID_SET;
    gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
    struct mag_conn *mc = NULL;
    int i;
    bool send_auth_header = true;

    type = ap_auth_type(req);
    if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) {
        return DECLINED;
    }

    req_cfg = mag_init_cfg(req);

    cfg = req_cfg->cfg;

    desired_mechs = req_cfg->desired_mechs;

    /* implicit auth for subrequests if main auth already happened */
    if (!ap_is_initial_req(req) && req->main != NULL) {
        type = ap_auth_type(req->main);
        if ((type != NULL) && (strcasecmp(type, "GSSAPI") == 0)) {
            /* warn if the subrequest location and the main request
             * location have different configs */
            if (cfg != ap_get_module_config(req->main->per_dir_config,
                                            &auth_gssapi_module)) {
                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0,
                              req, "Subrequest authentication bypass on "
                                   "location with different configuration!");
            }
            if (req->main->user) {
                req->user = apr_pstrdup(req->pool, req->main->user);
                return OK;
            } else {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                              "The main request is tasked to establish the "
                              "security context, can't proceed!");
                return HTTP_UNAUTHORIZED;
            }
        } else {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
                          "Subrequest GSSAPI auth with no auth on the main "
                          "request. This operation may fail if other "
                          "subrequests already established a context or the "
                          "mechanism requires multiple roundtrips.");
        }
    }

    if (cfg->ssl_only) {
        if (!mag_conn_is_https(req->connection)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Not a TLS connection, refusing to authenticate!");
            goto done;
        }
    }

    if (cfg->gss_conn_ctx) {
        mc = (struct mag_conn *)ap_get_module_config(
                                                req->connection->conn_config,
                                                &auth_gssapi_module);
        if (!mc) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
                          "Failed to retrieve connection context!");
            goto done;
        }
    }

    /* if available, session always supersedes connection bound data */
    if (req_cfg->use_sessions) {
        mag_check_session(req_cfg, &mc);
    }

    auth_header = apr_table_get(req->headers_in, req_cfg->req_proto);

    if (mc) {
        if (mc->established &&
            (auth_header == NULL) &&
            (mc->auth_type != AUTH_TYPE_BASIC)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
                          "Already established context found!");
            mag_set_req_data(req, cfg, mc);
            ret = OK;
            goto done;
        }
        pctx = &mc->ctx;
    } else {
        /* no preserved mc, create one just for this request */
        mc = mag_new_conn_ctx(req->pool);
        pctx = &ctx;
    }

    /* We can proceed only if we do have an auth header */
    if (!auth_header) goto done;

    auth_header_type = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_type) goto done;

    /* We got auth header, sending auth header would mean re-auth */
    send_auth_header = !cfg->negotiate_once;

    for (i = 0; auth_types[i] != NULL; i++) {
        if (strcasecmp(auth_header_type, auth_types[i]) == 0) {
            auth_type = i;
            break;
        }
    }

    switch (auth_type) {
    case AUTH_TYPE_NEGOTIATE:
        if (!parse_auth_header(req->pool, &auth_header, &input)) {
            goto done;
        }
        break;
    case AUTH_TYPE_BASIC:
        if (!cfg->use_basic_auth) {
            goto done;
        }

        ba_pwd.value = ap_pbase64decode(req->pool, auth_header);
        if (!ba_pwd.value) goto done;
        ba_user.value = ap_getword_nulls_nc(req->pool,
                                            (char **)&ba_pwd.value, ':');
        if (!ba_user.value) goto done;

        if (((char *)ba_user.value)[0] == '\0' ||
            ((char *)ba_pwd.value)[0] == '\0') {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Invalid empty user or password for Basic Auth");
            goto done;
        }
        ba_user.length = strlen(ba_user.value);
        ba_pwd.length = strlen(ba_pwd.value);

        if (mc->is_preserved && mc->established &&
            mag_basic_check(req_cfg, mc, ba_user, ba_pwd)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
                          "Already established BASIC AUTH context found!");
            mag_set_req_data(req, cfg, mc);
            ret = OK;
            goto done;
        }

        break;

    case AUTH_TYPE_RAW_NTLM:
        if (!is_mech_allowed(desired_mechs, gss_mech_ntlmssp,
                             cfg->gss_conn_ctx)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
                          "NTLM Authentication is not allowed!");
            goto done;
        }

        if (!parse_auth_header(req->pool, &auth_header, &input)) {
            goto done;
        }

        desired_mechs = discard_const(gss_mech_set_ntlmssp);
        break;

    default:
        goto done;
    }

    if (mc->established) {
        /* if we are re-authenticating make sure the conn context
         * is cleaned up so we do not accidentally reuse an existing
         * established context */
        mag_conn_clear(mc);
    }

    mc->auth_type = auth_type;

#ifdef HAVE_CRED_STORE
    if (use_s4u2proxy(req_cfg)) {
        cred_usage = GSS_C_BOTH;
    }
#endif

    if (auth_type == AUTH_TYPE_BASIC) {
        if (mag_auth_basic(req, cfg, ba_user, ba_pwd,
                           &client, &mech_type,
                           &delegated_cred, &vtime)) {
            goto complete;
        }
        goto done;
    }

    if (!mag_acquire_creds(req, cfg, desired_mechs,
                           cred_usage, &acquired_cred, NULL)) {
        goto done;
    }

    if (auth_type == AUTH_TYPE_NEGOTIATE &&
        cfg->allowed_mechs != GSS_C_NO_OID_SET) {
        maj = gss_set_neg_mechs(&min, acquired_cred, cfg->allowed_mechs);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
                          mag_error(req, "gss_set_neg_mechs() failed",
                                    maj, min));
            goto done;
        }
    }

    maj = gss_accept_sec_context(&min, pctx, acquired_cred,
                                 &input, GSS_C_NO_CHANNEL_BINDINGS,
                                 &client, &mech_type, &output, NULL, &vtime,
                                 &delegated_cred);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
                      mag_error(req, "gss_accept_sec_context() failed",
                                maj, min));
        goto done;
    } else if (maj == GSS_S_CONTINUE_NEEDED) {
        if (!mc->is_preserved) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Mechanism needs continuation but neither "
                          "GssapiConnectionBound nor "
                          "GssapiUseSessions are available");
            gss_release_buffer(&min, &output);
            output.length = 0;
        }
        /* auth not complete send token and wait next packet */
        goto done;
    }

complete:
    maj = gss_display_name(&min, client, &name, NULL);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
                      mag_error(req, "gss_display_name() failed",
                                maj, min));
        goto done;
    }

    mc->gss_name = apr_pstrndup(req->pool, name.value, name.length);
    if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
        vtime = MIN_SESS_EXP_TIME;
    }
    mc->expiration = time(NULL) + vtime;

    mag_get_name_attributes(req, cfg, client, mc);

#ifdef HAVE_CRED_STORE
    if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
        char *ccache_path;

        mc->ccname = 0;
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
                      "requester: %s", mc->gss_name);

        ccache_path = get_ccache_name(req, cfg->deleg_ccache_dir, mc->gss_name,
                                      cfg->deleg_ccache_unique, mc);
        if (ccache_path == NULL) {
            goto done;
        }

        mag_store_deleg_creds(req, ccache_path, delegated_cred);
        mc->delegated = true;

        if (!req_cfg->use_sessions && cfg->deleg_ccache_unique) {
            /* queue removing ccache to avoid littering filesystem */
            apr_pool_cleanup_register(mc->pool, ccache_path,
                                      (int (*)(void *)) unlink,
                                      apr_pool_cleanup_null);
        }

        /* extract filename from full path */
        mc->ccname = strrchr(ccache_path, '/') + 1;
    }
#endif

    if (cfg->map_to_local) {
        maj = gss_localname(&min, client, mech_type, &lname);
        if (maj != GSS_S_COMPLETE) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
                          mag_error(req, "gss_localname() failed", maj, min));
            goto done;
        }
        mc->user_name = apr_pstrndup(req->pool, lname.value, lname.length);
    } else {
        mc->user_name = apr_pstrdup(mc->pool, mc->gss_name);
    }

    mc->established = true;
    if (auth_type == AUTH_TYPE_BASIC) {
        mag_basic_cache(req_cfg, mc, ba_user, ba_pwd);
    }
    if (req_cfg->use_sessions) {
        mag_attempt_session(req_cfg, mc);
    }

    /* Now set request data and env vars */
    mag_set_req_data(req, cfg, mc);

    if (req_cfg->send_persist)
        apr_table_set(req->headers_out, "Persistent-Auth",
            cfg->gss_conn_ctx ? "true" : "false");

    ret = OK;

done:

    if ((auth_type != AUTH_TYPE_BASIC) && (output.length != 0)) {
        int prefixlen = strlen(mag_str_auth_type(auth_type)) + 1;
        replen = apr_base64_encode_len(output.length) + 1;
        reply = apr_pcalloc(req->pool, prefixlen + replen);
        if (reply) {
            memcpy(reply, mag_str_auth_type(auth_type), prefixlen - 1);
            reply[prefixlen - 1] = ' ';
            apr_base64_encode(&reply[prefixlen], output.value, output.length);
            apr_table_add(req->err_headers_out, req_cfg->rep_proto, reply);
        }
    } else if (ret == HTTP_UNAUTHORIZED) {
        if (send_auth_header) {
            apr_table_add(req->err_headers_out,
                          req_cfg->rep_proto, "Negotiate");
            if (is_mech_allowed(desired_mechs, gss_mech_ntlmssp,
                                cfg->gss_conn_ctx)) {
                apr_table_add(req->err_headers_out, req_cfg->rep_proto,
                              "NTLM");
            }
        }
        if (cfg->use_basic_auth) {
            apr_table_add(req->err_headers_out, req_cfg->rep_proto,
                          apr_psprintf(req->pool, "Basic realm=\"%s\"",
                                       ap_auth_name(req)));
        }
    }

    if (ctx != GSS_C_NO_CONTEXT)
        gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER);
    gss_release_cred(&min, &acquired_cred);
    gss_release_cred(&min, &delegated_cred);
    gss_release_buffer(&min, &output);
    gss_release_name(&min, &client);
    gss_release_buffer(&min, &name);
    gss_release_buffer(&min, &lname);
    return ret;
}
Esempio n. 4
0
int check_digest_response(struct pmsg *msg, char *realm,
						  char *username, char *password)
{
	char *hdr, expected[33], token[33];
	struct digest_auth_info auth;
	char *v[2] = { token, digest_secret };
	struct timeval now;
	char strPassword[64] = {0};

	memset(&auth, 0, sizeof(auth));

	if (!(hdr = get_header(msg, "authorization"))) return -1;

	if (parse_auth_header(hdr, &auth) < 0) {
		spook_log(SL_VERBOSE,
				  "digest-auth: unable to parse www-authenticate header");
		return -1;
	}

	/* Case-sensitive realm (should just be parroted back by the client) */
	if (strcmp(auth.realm, realm)) {
		spook_log(SL_VERBOSE,
				  "digest-auth: realm \"%s\" is not correct",
				  auth.realm);
		return -1;
	}

	/* Case-insensitive usernames */
	if (strlen(username) > 0) {
		if (strcasecmp(auth.username, username)) {
			spook_log(SL_VERBOSE,
					  "digest-auth: username \"%s\" is not correct",
					  auth.username);
			return -1;
		}
	}

	/* The client may or may not have included the digest-uri directive */
	if (! auth.uri[0]) {
		if (strlen(msg->sl.req.uri) >= sizeof(auth.uri)) {
			spook_log(SL_WARN,
					  "URI is too long for digest-auth!");
			return -1;
		}

		strcpy(auth.uri, msg->sl.req.uri);
	}

	/* Figure out what the response should be */
	if (strlen(username) > 0 && strlen(password) > 0)
		create_response(expected, &auth, msg->sl.req.method, password);
	else
		create_response(expected, &auth, msg->sl.req.method, strPassword);

	if (strcasecmp(auth.response, expected)) {
		spook_log(SL_VERBOSE, "digest-auth: incorrect password");
		return -1;
	}

	/* From this point on, it appears that the client knows the correct
	 * username and password, it's just a matter of whether the nonce
	 * was generated by us and has not yet expired.  If the nonce is
	 * invalid, we can use the "stale=true" directive in the 401 so
	 * the client can retry authentication with the same username and
	 * password, if it still has it. */

	if (! secret_created || strlen(auth.nonce) != 64) {
		spook_log(SL_VERBOSE, "digest-auth: this is not our nonce!");
		return 0;
	}

	/* Check that the nonce validates against our secret */
	strncpy(token, auth.nonce, 32);
	token[32] = 0;
	md5_hash(v, 2, expected);

	if (strcmp(auth.nonce + 32, expected)) {
		spook_log(SL_VERBOSE, "digest-auth: this is not our nonce!");
		return 0;
	}

	/* Check that the nonce is not more than 15 seconds old */
	gettimeofday(&now, NULL);

	if (now.tv_sec > get_hex_u32(token) + 15) {
		spook_log(SL_VERBOSE,
				  "digest-auth: nonce is more than 15 seconds old");
		return 0;
	}

	spook_log(SL_VERBOSE, "digest-auth authentication succeeded");
	return 1;
}