blob: 46157293ba7c3792c108ea0177ba6ee53a9ecd87 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <axis2_handler_desc.h>
#include <axis2_core_utils.h>
#include <axiom_soap_envelope.h>
#include <axiom_soap_body.h>
#include <trust_constants.h>
#include <axis2_engine.h>
#include <trust_rst.h>
#include <trust_rstr.h>
#include <rahas_request_processor.h>
#include <rampart_handler_util.h>
#include <rampart_constants.h>
static axis2_status_t
rahas_send_reply(
axiom_node_t *body_node,
const axutil_env_t *env,
axis2_msg_ctx_t *msg_ctx);
static void
rahas_find_trust_version_specific_details(
const axutil_env_t *env,
axis2_char_t *action,
int *trust_version,
int *request_type,
axis2_char_t **reply_action);
static axiom_node_t *
rahas_request_security_token(
const axutil_env_t *env,
axiom_node_t *node,
axis2_msg_ctx_t *msg_ctx,
int trust_version,
int request_type);
axis2_status_t AXIS2_CALL
rahas_in_handler_invoke(
struct axis2_handler *handler,
const axutil_env_t *env,
struct axis2_msg_ctx *msg_ctx);
AXIS2_EXTERN axis2_handler_t *AXIS2_CALL
rahas_in_handler_create(
const axutil_env_t *env,
axutil_string_t *name)
{
axis2_handler_t *handler = NULL;
AXIS2_ENV_CHECK(env, NULL);
handler = axis2_handler_create(env);
if (!handler)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas] Cannot create in-handler.");
return NULL;
}
/*Set the function to invoke*/
axis2_handler_set_invoke(handler, env, rahas_in_handler_invoke);
return handler;
}
axis2_status_t AXIS2_CALL
rahas_in_handler_invoke(
struct axis2_handler *handler,
const axutil_env_t *env,
struct axis2_msg_ctx *msg_ctx)
{
axutil_string_t *soap_action = NULL;
axis2_char_t *action = NULL;
axiom_soap_envelope_t *soap_envelope = NULL;
axiom_soap_body_t *soap_body = NULL;
axiom_node_t *body_node = NULL;
axiom_node_t *body_child_node = NULL;
axiom_node_t *reply_body_child_node = NULL;
int trust_version = TRUST_VERSION_INVALID;
int request_type = SECCONV_ACTION_INVALID;
axis2_char_t *reply_action = NULL;
AXIS2_PARAM_CHECK(env->error, msg_ctx, AXIS2_FAILURE);
AXIS2_LOG_INFO(env->log, "[rahas]Rahas in handler is called. ");
/* check whether this is server side. Rahas is not needed in client side */
if(!axis2_msg_ctx_get_server_side(msg_ctx, env))
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Rahas is engaged in client side. It is not supported in client side.");
return AXIS2_FAILURE;
}
/* check whether the action is valid secure conversation related action. First check soap action
* and if it is not valid, check for wsa action. To proceed, either should be valid.
* If neither of them are valid, then it is not a secure conversation request. It could be
* application message. So return success. If action is valid secure conversation action, then
* we can find trust version using action
*/
soap_action = axis2_msg_ctx_get_soap_action(msg_ctx, env);
if(soap_action)
{
action = (axis2_char_t *)axutil_string_get_buffer(soap_action, env);
}
if(!action)
{
action = (axis2_char_t *)axis2_msg_ctx_get_wsa_action(msg_ctx, env);
}
if(action)
{
rahas_find_trust_version_specific_details(
env, action, &trust_version, &request_type, &reply_action);
}
if(!trust_version)
{
/* this is not a secure conversation related message. So can return without proceeding */
AXIS2_LOG_INFO(env->log, "[rahas] Message with action %s will not be processed by rahas.",
action);
return AXIS2_SUCCESS;
}
soap_envelope = axis2_msg_ctx_get_soap_envelope(msg_ctx, env);
if(!soap_envelope)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]SOAP envelope cannot be found.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
return AXIS2_FAILURE;
}
soap_body = axiom_soap_envelope_get_body(soap_envelope, env);
if(!soap_body)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]SOAP body cannot be found.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
return AXIS2_FAILURE;
}
body_node = axiom_soap_body_get_base_node(soap_body, env);
if(!body_node)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]SOAP body node cannot be found.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
return AXIS2_FAILURE;
}
body_child_node = axiom_node_get_first_element(body_node, env);
if(!body_child_node)
{
/* body node is empty. Secure conversation related messages should have a non empty body */
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]SOAP body node is empty.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
return AXIS2_FAILURE;
}
/* We got a valid secure conversation related message. Check the request and build the reply */
reply_body_child_node = rahas_request_security_token(
env, body_child_node, msg_ctx, trust_version, request_type);
if(!reply_body_child_node)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot process SecureConversation request.");
return AXIS2_FAILURE;
}
/* set the reply action in to message context */
axis2_msg_ctx_set_wsa_action(msg_ctx, env, reply_action);
/* no need to proceed in in_flow. We can send above node as response. When axis2 get the
* control from here, it should continue to out_flow and send the reply
*/
if(rahas_send_reply(reply_body_child_node, env, msg_ctx) != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]Cannot send reply from rahas.");
return AXIS2_FAILURE;
}
return AXIS2_SUCCESS;
}
static axis2_status_t
rahas_send_reply(
axiom_node_t *body_node,
const axutil_env_t *env,
axis2_msg_ctx_t *msg_ctx)
{
axis2_msg_ctx_t *out_msg_ctx = NULL;
axiom_soap_envelope_t *soap_envelope = NULL;
axiom_soap_body_t *soap_body = NULL;
axiom_node_t *body_parent_node = NULL;
axis2_engine_t *engine = NULL;
/* find soap envelop and set the body node */
out_msg_ctx = axis2_core_utils_create_out_msg_ctx(env, msg_ctx);
if(!out_msg_ctx)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI, "[rahas]Cannot create out message context.");
return AXIS2_FAILURE;
}
soap_envelope = axis2_msg_ctx_get_soap_envelope(out_msg_ctx, env);
if(!soap_envelope)
{
int soap_version = AXIOM_SOAP12;
if(axis2_msg_ctx_get_is_soap_11(msg_ctx, env))
{
soap_version = AXIOM_SOAP11;
}
soap_envelope = axiom_soap_envelope_create_default_soap_envelope(env, soap_version);
axis2_msg_ctx_set_soap_envelope(out_msg_ctx, env, soap_envelope);
}
soap_body = axiom_soap_envelope_get_body(soap_envelope, env);
if(!soap_body)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]SOAP body cannot be found from out message context.");
return AXIS2_FAILURE;
}
body_parent_node = axiom_soap_body_get_base_node(soap_body, env);
if(!body_parent_node)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]SOAP body node cannot be found from out message context.");
return AXIS2_FAILURE;
}
axiom_node_add_child(body_parent_node, env, body_node);
/* Now we have to tell axis2 not to continue in in_flow, go to out_flow */
axis2_msg_ctx_set_paused(msg_ctx, env, AXIS2_TRUE);
axis2_msg_ctx_set_flow(out_msg_ctx, env, AXIS2_OUT_FLOW);
/* Send the reply */
engine = axis2_engine_create(env, axis2_msg_ctx_get_conf_ctx(out_msg_ctx, env));
axis2_engine_send(engine, env, out_msg_ctx);
if(engine)
{
axis2_engine_free(engine, env);
}
return AXIS2_SUCCESS;
}
static axiom_node_t *
rahas_request_security_token(
const axutil_env_t *env,
axiom_node_t *node,
axis2_msg_ctx_t *msg_ctx,
int trust_version,
int request_type)
{
axis2_char_t *trust_xml_ns = NULL;
trust_rst_t* rst = NULL;
trust_rstr_t* rstr = NULL;
axiom_node_t* rstr_node = NULL;
axis2_status_t status = AXIS2_SUCCESS;
/* Get trust version specific values */
if(trust_version == TRUST_VERSION_05_02)
{
trust_xml_ns = TRUST_WST_XMLNS_05_02;
}
else
{
trust_xml_ns = TRUST_WST_XMLNS_05_12;
}
/* create rst and set trust version. Trust version is needed to populate rst structure with
* given node. After setting them, populate rst structure */
rst = trust_rst_create(env);
if(!rst)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot create RequestSecurityToken structure. Insufficient memory.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
return NULL;
}
trust_rst_set_wst_ns_uri(rst, env, trust_xml_ns);
status = trust_rst_populate_rst(rst, env, node);
if(status != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot populate RequestSecurityToken structure. Given message might not "
"be a valid security token request. ");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
trust_rst_free(rst, env);
return NULL;
}
/*create rstr and populate*/
rstr = trust_rstr_create(env);
if(!rstr)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot create RequestSecurityTokenResponse structure.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
trust_rst_free(rst, env);
return NULL;
}
/* set request type and namespace */
trust_rstr_set_wst_ns_uri(rstr, env, trust_xml_ns);
trust_rstr_set_request_type(rstr, env, trust_rst_get_request_type(rst, env));
/* call request processor */
if(request_type == SECCONV_ACTION_ISSUE)
{
status = rahas_process_issue_request(env, rst, rstr, msg_ctx, trust_version);
}
else if(request_type == SECCONV_ACTION_CANCEL)
{
/* TODO implement cancel method */
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Inidentified security context token request type. "
"Only 'issue' is supported.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
status = AXIS2_FAILURE;
}
else
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Inidentified security context token request type. "
"Only 'issue' and 'cancel' are supported.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_INVALID,
"The request was invalid or malformed", RAMPART_FAULT_TRUST_REQUEST_INVALID, msg_ctx);
status = AXIS2_FAILURE;
}
if(status != AXIS2_SUCCESS)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Cannot Process security context token request.");
trust_rst_free(rst, env);
trust_rstr_free(rstr, env);
return NULL;
}
/* build the rstr node */
rstr_node = trust_rstr_build_rstr(rstr, env, NULL);
if(!rstr_node)
{
AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
"[rahas]Creation of RequestSecurityTokenResponse node failed.");
rampart_create_fault_envelope(env, RAMPART_FAULT_TRUST_REQUEST_FAILED,
"The specified request failed", RAMPART_FAULT_TRUST_REQUEST_FAILED, msg_ctx);
}
/* clear stuff */
trust_rstr_free(rstr, env);
trust_rst_free(rst, env);
return rstr_node;
}
/* This method will find trust_version, request_type and reply_action based on given action.
* trust_version, request_type, reply_action are output parameters. action is input parameter */
static void
rahas_find_trust_version_specific_details(
const axutil_env_t *env,
axis2_char_t *action,
int *trust_version,
int *request_type,
axis2_char_t **reply_action)
{
if(!axutil_strcmp(action, SECCONV_200502_REQUEST_ISSUE_ACTION))
{
*trust_version = TRUST_VERSION_05_02;
*request_type = SECCONV_ACTION_ISSUE;
*reply_action = SECCONV_200502_REPLY_ISSUE_ACTION;
}
else if(!axutil_strcmp(action, SECCONV_200502_REQUEST_CANCEL_ACTION))
{
*trust_version = TRUST_VERSION_05_02;
*request_type = SECCONV_ACTION_CANCEL;
*reply_action = SECCONV_200502_REPLY_CANCEL_ACTION;
}
else if(!axutil_strcmp(action, SECCONV_200512_REQUEST_ISSUE_ACTION))
{
*trust_version = TRUST_VERSION_05_12;
*request_type = SECCONV_ACTION_ISSUE;
*reply_action = SECCONV_200512_REPLY_ISSUE_ACTION;
}
else if(!axutil_strcmp(action, SECCONV_200512_REQUEST_CANCEL_ACTION))
{
*trust_version = TRUST_VERSION_05_12;
*request_type = SECCONV_ACTION_CANCEL;
*reply_action = SECCONV_200512_REPLY_CANCEL_ACTION;
}
/* TODO: we still don't support amend and renew. Implement them */
}