[asterisk-commits] mmichelson: branch mmichelson/authenticate r380754 - in /team/mmichelson/auth...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Jan 31 18:23:44 CST 2013


Author: mmichelson
Date: Thu Jan 31 18:23:40 2013
New Revision: 380754

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=380754
Log:
Massive changes to authentication API.

The authenticator callbacks have been changed. The authentication_required()
callback remains, but the other two have been replaced with a single general
check_authentication() callback. This gives more freedom to the authenticator
to authenticate in the fashion that fits best. The old method was awkwardly
forcing digest authentication on the authenticator, or forcing them to put
a square peg in a round hole in order to use a different scheme.

All digest-related authentication lives locally in res_sip_authenticator
(that will likely see a name change soon).

res_sip_authenticator also has some hardcoded data in order to do some testing.
And hey, authentication worked properly when presented with the correct
credentials!

I also changed the storage method of the registered SIP authenticator, mainly
because I was completely misusing an ao2_global_obj. It can potentially change
back to using a global object, but for now, just trying to get something working,
I'm keeping it simple.


Modified:
    team/mmichelson/authenticate/include/asterisk/res_sip.h
    team/mmichelson/authenticate/main/astobj2.c
    team/mmichelson/authenticate/res/res_sip.c
    team/mmichelson/authenticate/res/res_sip_authenticator.c
    team/mmichelson/authenticate/res/res_sip_session.c

Modified: team/mmichelson/authenticate/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/authenticate/include/asterisk/res_sip.h?view=diff&rev=380754&r1=380753&r2=380754
==============================================================================
--- team/mmichelson/authenticate/include/asterisk/res_sip.h (original)
+++ team/mmichelson/authenticate/include/asterisk/res_sip.h Thu Jan 31 18:23:40 2013
@@ -234,60 +234,19 @@
 struct ast_sip_endpoint *ast_sip_get_endpoint_from_location(const char *addr);
  
 /*!
- * \brief Data used for creating authentication challenges.
- * 
- * This data gets populated by an authenticator's get_authentication_credentials() callback.
- */
-struct ast_sip_digest_challenge_data {
-    /*!
-     * The realm to which the user is authenticating. An authenticator MUST fill this in.
-     */
-    const char *realm;
-    /*!
-     * Indicates whether the username and password are in plaintext or encoded as MD5.
-     * If this is non-zero, then the data is an MD5 sum. Otherwise, the username and password are plaintext.
-     * Authenticators MUST set this.
-     */
-    int is_md5;
-    /*!
-     * This is the actual username and secret. The is_md5 field is used to determine which member
-     * of the union is to be used when creating the authentication challenge. In other words, if
-     * is_md5 is non-zero, then we will use the md5 field of the auth union. Otherwise, we will
-     * use the plain struct in the auth union.
-     * Authenticators MUST fill in the appropriate field of the union.
-     */
-    union {
-        /*!
-         * Structure containing the username and password to encode in a digest authentication challenge.
-         */
-        struct {
-            const char *username;
-            const char *password;
-        } plain;
-        /*!
-         * An MD5-encoded string that incorporates the username and password.
-         */
-        const char *md5;
-    } auth;
-    /*!
-     * Domain for which the authentication challenge is being sent. This corresponds to the "domain=" portion of
-     * a digest authentication.
-     *
-     * Authenticators do not have to fill in this field since it is an optional part of a digest.
-     */
-    const char *domain;
-    /*!
-     * Opaque string for digest challenge. This corresponds to the "opaque=" portion of a digest authentication.
-     * Authenticators do not have to fill in this field. If an authenticator does not fill it in, Asterisk will provide one.
-     */
-    const char *opaque;
-    /*!
-     * Nonce string for digest challenge. This corresponds to the "nonce=" portion of a digest authentication.
-     * Authenticators do not have to fill in this field. If an authenticator does not fill it in, Asterisk will provide one.
-     */
-    const char *nonce;
-};
- 
+ * \brief Possible returns from ast_sip_check_authentication
+ */
+enum ast_sip_check_auth_result {
+    /*! Authentication needs to be challenged */
+    AST_SIP_AUTHENTICATION_CHALLENGE,
+    /*! Authentication succeeded */
+    AST_SIP_AUTHENTICATION_SUCCESS,
+    /*! Authentication failed */
+    AST_SIP_AUTHENTICATION_FAILED,
+    /*! Authentication encountered some internal error */
+    AST_SIP_AUTHENTICATION_ERROR,
+};
+
 /*!
  * \brief An interchangeable way of handling digest authentication for SIP.
  * 
@@ -301,16 +260,17 @@
      * See ast_sip_requires_authentication for more details
      */
     int (*requires_authentication)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-    /*!
-     * \brief Attempt to authenticate the incoming request
-     * See ast_sip_authenticate_request for more details
-     */
-    int (*authenticate_request)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
-    /*!
-     * \brief Get digest authentication details
-     * See ast_sip_get_authentication_credentials for more details
-    */
-    int (*get_authentication_credentials)(struct ast_sip_endpoint *endpoint, struct ast_sip_digest_challenge_data *challenge);
+	/*!
+	 * \brief Check that an incoming request passes authentication.
+	 *
+	 * The tdata parameter is useful for adding information such as digest challenges.
+	 *
+	 * \param endpoint The endpoint sending the incoming request
+	 * \param rdata The incoming request
+	 * \param tdata Tentative outgoing request.
+	 */
+	enum ast_sip_check_auth_result (*check_authentication)(struct ast_sip_endpoint *endpoint,
+			pjsip_rx_data *rdata, pjsip_tx_data *tdata);
 };
  
 /*!
@@ -536,71 +496,20 @@
 int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
  
 /*!
- * \brief Authenticate an inbound SIP request
- *
- * This calls into the registered authenticator's authenticate_request callback
- * in order to determine if the request contains proper credentials as to be
- * authenticated.
- *
- * If there is no registered authenticator, then the request will assumed to be
- * authenticated properly.
- *
- * \param endpoint The endpoint from which the request originates
- * \param rdata The incoming SIP request
- * \retval 0 Successfully authenticated
- * \retval nonzero Failure to authenticate
- */
-int ast_sip_authenticate_request(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
- 
-/*!
- * \brief Get authentication credentials in order to challenge a request
- *
- * This calls into the registered authenticator's get_authentication_credentials
- * callback in order to get credentials required for challenging a request.
- *
- * \param endpoint The endpoint whose credentials are being gathered
- * \param[out] challenge The necessary data in order to be able to challenge a request
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_get_authentication_credentials(struct ast_sip_endpoint *endpoint, struct ast_sip_digest_challenge_data *challenge);
- 
-/*!
- * \brief Possible returns from ast_sip_check_authentication
- */
-enum ast_sip_check_auth_result {
-    /*! Authentication challenge sent */
-    AST_SIP_AUTHENTICATION_CHALLENGE_SENT,
-    /*! Authentication succeeded */
-    AST_SIP_AUTHENTICATION_SUCCESS,
-    /*! Authentication failed */
-    AST_SIP_AUTHENTICATION_FAILED,
-    /*! Authentication not required */
-    AST_SIP_AUTHENTICATION_NOT_REQUIRED,
-};
- 
-/*!
- * \brief Shortcut routine to check for authentication of an incoming request
- *
- * This is a wrapper that will call into a registered authenticator to see if a request
- * should be authenticated. Then if it should be, will attempt to authenticate. If the
- * request cannot be authenticated, then a challenge will be sent. Calling this can be
- * a suitable substitute for calling ast_sip_requires_authentication(),
- * ast_sip_authenticate_request(), and ast_sip_get_authentication_credentials()
+ * \brief Method to determine authentication status of an incoming request
+ *
+ * This will call into a registered authenticator. The registered authenticator will
+ * do what is necessary to determine whether the incoming request passes authentication.
+ * A tentative response is passed into this function so that if, say, a digest authentication
+ * challenge should be sent in the ensuing response, it can be added to the response.
  *
  * \param endpoint The endpoint from the request was sent
  * \param rdata The request to potentially authenticate
+ * \param tdata Tentative response to the request
  * \return The result of checking authentication.
  */
-enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
- 
-/*!
- * \brief Add digest information to an authentication challenge
- *
- * \param challenge Details to help in constructing a WWW-Authenticate header
- * \param tdata The challenge to add the digest to
- */
-void ast_sip_add_digest_to_challenge(struct ast_sip_digest_challenge_data *challenge, pjsip_tx_data *tdata);
+enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint,
+		pjsip_rx_data *rdata, pjsip_tx_data *tdata);
  
 /*!
  * \brief Determine the endpoint that has sent a SIP message

Modified: team/mmichelson/authenticate/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/authenticate/main/astobj2.c?view=diff&rev=380754&r1=380753&r2=380754
==============================================================================
--- team/mmichelson/authenticate/main/astobj2.c (original)
+++ team/mmichelson/authenticate/main/astobj2.c Thu Jan 31 18:23:40 2013
@@ -525,6 +525,7 @@
 	struct astobj2 *obj = INTERNAL_OBJ(user_data);
 
 	if (obj == NULL) {
+		ast_backtrace();
 		ast_assert(0);
 		return -1;
 	}

Modified: team/mmichelson/authenticate/res/res_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/authenticate/res/res_sip.c?view=diff&rev=380754&r1=380753&r2=380754
==============================================================================
--- team/mmichelson/authenticate/res/res_sip.c (original)
+++ team/mmichelson/authenticate/res/res_sip.c Thu Jan 31 18:23:40 2013
@@ -69,95 +69,48 @@
 	ast_debug(1, "Unregistered SIP service %.*s\n", (int) pj_strlen(&module->name), pj_strbuf(&module->name));
 }
 
-AO2_GLOBAL_OBJ_STATIC(registered_authenticator);
+static struct ast_sip_authenticator *registered_authenticator;
 
 int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
 {
-	RAII_VAR(struct ast_sip_authenticator *, reg, ao2_global_obj_ref(registered_authenticator), ao2_cleanup);
-	if (reg) {
-		ast_log(LOG_WARNING, "Authenticator %p is already registered. Cannot register a new one\n", reg);
-		return -1;
-	}
-	ao2_global_obj_replace_unref(registered_authenticator, auth);
+	if (registered_authenticator) {
+		ast_log(LOG_WARNING, "Authenticator %p is already registered. Cannot register a new one\n", registered_authenticator);
+		return -1;
+	}
+	registered_authenticator = auth;
 	ast_debug(1, "Registered SIP authenticator module %p\n", auth);
 	return 0;
 }
 
 void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
 {
-	RAII_VAR(struct ast_sip_authenticator *, reg, ao2_global_obj_ref(registered_authenticator), ao2_cleanup);
-	if (auth != reg) {
+	if (registered_authenticator != auth) {
 		ast_log(LOG_WARNING, "Trying to unregister authenticator %p but authenticator %p registered\n",
-				auth, reg);
+				auth, registered_authenticator);
 		return;
 	}
-	ao2_global_obj_release(registered_authenticator);
+	registered_authenticator = NULL;
 	ast_debug(1, "Unregistered SIP authenticator %p\n", auth);
 }
 
 int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 {
-	RAII_VAR(struct ast_sip_authenticator *, reg, ao2_global_obj_ref(registered_authenticator), ao2_cleanup);
-	if (!reg) {
+	if (!registered_authenticator) {
 		ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is not required\n");
 		return 0;
 	}
 
-	return reg->requires_authentication(endpoint, rdata);
-}
-
-int ast_sip_authenticate_request(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	RAII_VAR(struct ast_sip_authenticator *, reg, ao2_global_obj_ref(registered_authenticator), ao2_cleanup);
-	if (!reg) {
-		ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming request authenticated properly\n");
+	return registered_authenticator->requires_authentication(endpoint, rdata);
+}
+
+enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint,
+		pjsip_rx_data *rdata, pjsip_tx_data *tdata)
+{
+	if (!registered_authenticator) {
+		ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming authentication is successful\n");
 		return 0;
 	}
-
-	return reg->authenticate_request(endpoint, rdata);
-}
-
-int ast_sip_get_authentication_credentials(struct ast_sip_endpoint *endpoint,
-		struct ast_sip_digest_challenge_data *challenge)
-{
-	RAII_VAR(struct ast_sip_authenticator *, reg, ao2_global_obj_ref(registered_authenticator), ao2_cleanup);
-	if (!reg) {
-		ast_log(LOG_WARNING, "No SIP authenticator registered. Assuming no authentication credentials\n");
-		return -1;
-	}
-
-	return reg->get_authentication_credentials(endpoint, challenge);
-}
-
-void ast_sip_add_digest_to_challenge(struct ast_sip_digest_challenge_data *challenge, pjsip_tx_data *tdata)
-{
-	pjsip_auth_srv auth_server;
-	pj_str_t realm;
-	pj_str_t nonce;
-	pj_str_t *nonce_ptr = NULL;
-	pj_str_t qop;
-	pj_str_t opaque;
-	pj_str_t *opaque_ptr = NULL;
-
-	pj_cstr(&realm, challenge->realm);
-	pj_cstr(&qop, "auth");
-	if (!ast_strlen_zero(challenge->opaque)) {
-		pj_cstr(&opaque, challenge->opaque);
-		opaque_ptr = &opaque;
-	}
-	if (!ast_strlen_zero(challenge->nonce)) {
-		pj_cstr(&nonce, challenge->nonce);
-		nonce_ptr = &nonce;
-	}
-
-	pjsip_auth_srv_init(tdata->pool, &auth_server, &realm, NULL, 0);
-	pjsip_auth_srv_challenge(&auth_server, &qop, nonce_ptr, opaque_ptr, PJ_FALSE, tdata);
-}
-
-enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
-{
-	/* XXX Stub */
-	return AST_SIP_AUTHENTICATION_SUCCESS;
+	return registered_authenticator->check_authentication(endpoint, rdata, tdata);
 }
 
 struct endpoint_identifier_list {

Modified: team/mmichelson/authenticate/res/res_sip_authenticator.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/authenticate/res/res_sip_authenticator.c?view=diff&rev=380754&r1=380753&r2=380754
==============================================================================
--- team/mmichelson/authenticate/res/res_sip_authenticator.c (original)
+++ team/mmichelson/authenticate/res/res_sip_authenticator.c Thu Jan 31 18:23:40 2013
@@ -32,26 +32,57 @@
 
 static int default_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 {
-	/* STUB */
-	return 0;
+	/* XXX While we are using hardcoded values, let's always claim that
+	 * the incoming request requires authentication
+	 */
+	return 1;
 }
 
-static int default_authenticate_request(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
+/* XXX For now, just use some hard-coded credentials. First step in this process is to
+ * be sure that authentication is working and that the API doesn't need adjustments. The
+ * next step will be figuring out the endpoint configuration needed in order for authentication
+ * to properly work.
+ */
+const char default_realm[] = "asterisk";
+const char default_username[] = "bob";
+const char default_password[] = "hunter2";
+
+static pj_status_t default_lookup(pj_pool_t *pool, const pj_str_t *realm,
+		const pj_str_t *acc_name, pjsip_cred_info *info)
 {
-	/* STUB */
-	return 0;
+	pj_strdup2(pool, &info->realm, default_realm);
+	pj_strdup2(pool, &info->username, default_username);
+	pj_strdup2(pool, &info->data, default_password);
+	info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
+	return PJ_SUCCESS;
 }
 
-static int default_get_authentication_credentials(struct ast_sip_endpoint *endpoint, struct ast_sip_digest_challenge_data *challenge)
+static enum ast_sip_check_auth_result default_check_auth(struct ast_sip_endpoint *endpoint,
+		pjsip_rx_data *rdata, pjsip_tx_data *tdata)
 {
-	/* STUB */
-	return -1;
+	pjsip_auth_srv auth_server;
+	pj_str_t realm;
+	pj_str_t qop;
+	int response_code;
+
+	pj_cstr(&realm, default_realm);
+	pj_cstr(&qop, "auth");
+
+	pjsip_auth_srv_init(tdata->pool, &auth_server, &realm, default_lookup, 0);
+
+	/* First thing's first, let's see if this request passes muster */
+	if (pjsip_auth_srv_verify(&auth_server, rdata, &response_code) == PJ_SUCCESS) {
+		return AST_SIP_AUTHENTICATION_SUCCESS;
+	}
+
+	/* Oh no! They couldn't authenticate. Well let's create a challenge for them. */
+	pjsip_auth_srv_challenge(&auth_server, &qop, NULL, NULL, PJ_FALSE, tdata);
+	return AST_SIP_AUTHENTICATION_CHALLENGE;
 }
 
 static struct ast_sip_authenticator default_authenticator = {
 	.requires_authentication = default_requires_authentication,
-	.authenticate_request = default_authenticate_request,
-	.get_authentication_credentials = default_get_authentication_credentials,
+	.check_authentication = default_check_auth,
 };
 
 static int load_module(void)

Modified: team/mmichelson/authenticate/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/authenticate/res/res_sip_session.c?view=diff&rev=380754&r1=380753&r2=380754
==============================================================================
--- team/mmichelson/authenticate/res/res_sip_session.c (original)
+++ team/mmichelson/authenticate/res/res_sip_session.c Thu Jan 31 18:23:40 2013
@@ -726,23 +726,21 @@
 	 */
 
 	if (ast_sip_requires_authentication(endpoint, rdata)) {
-		if (ast_sip_authenticate_request(endpoint, rdata)) {
-			struct ast_sip_digest_challenge_data challenge_data;
-			if (pjsip_inv_initial_answer(inv_session, rdata, 401, NULL, NULL, &tdata) != PJ_SUCCESS) {
-				pjsip_inv_terminate(inv_session, 500, PJ_TRUE);
-				return;
-			}
-			memset(&challenge_data, 0, sizeof(challenge_data));
-			if (ast_sip_get_authentication_credentials(endpoint, &challenge_data)) {
-				if (pjsip_inv_answer(inv_session, 500, NULL, NULL, &tdata) != PJ_SUCCESS) {
-					ast_sip_session_send_response(session, tdata);
-				} else {
-					pjsip_inv_terminate(inv_session, 500, PJ_TRUE);
-				}
-				return;
-			}
-			ast_sip_add_digest_to_challenge(&challenge_data, tdata);
-			ast_sip_session_send_response(session, tdata);
+		pjsip_inv_initial_answer(inv_session, rdata, 401, NULL, NULL, &tdata);
+		switch (ast_sip_check_authentication(endpoint, rdata, tdata)) {
+		case AST_SIP_AUTHENTICATION_CHALLENGE:
+			/* Send the 401 we created for them */
+			pjsip_inv_send_msg(inv_session, tdata);
+			return;
+		case AST_SIP_AUTHENTICATION_SUCCESS:
+			break;
+		case AST_SIP_AUTHENTICATION_FAILED:
+			pjsip_inv_answer(inv_session, 403, NULL, NULL, &tdata);
+			pjsip_inv_send_msg(inv_session, tdata);
+			return;
+		case AST_SIP_AUTHENTICATION_ERROR:
+			pjsip_inv_answer(inv_session, 500, NULL, NULL, &tdata);
+			pjsip_inv_send_msg(inv_session, tdata);
 			return;
 		}
 	}




More information about the asterisk-commits mailing list