keremoge commented on code in PR #14002: URL: https://github.com/apache/apisix/pull/14002#discussion_r4195402253
########## apisix/plugins/soap-signer/signer.lua: ########## @@ -0,0 +1,389 @@ +-- +-- 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. +-- +local random = require("resty.random") +local resty_string = require("resty.string") + +local algorithms = require("apisix.plugins.signing.algorithms") +local credentials = require("apisix.plugins.signing.credentials") +local xml = require("apisix.plugins.signing.xml") + +local ipairs = ipairs +local ngx = ngx +local os = os +local encode_base64 = ngx.encode_base64 + +local SOAP11 = "http://schemas.xmlsoap.org/soap/envelope/" +local SOAP12 = "http://www.w3.org/2003/05/soap-envelope" +local SOAP12_ULTIMATE_RECEIVER = SOAP12 .. "/role/ultimateReceiver" +local WSSE = "http://docs.oasis-open.org/wss/2004/01/" + .. "oasis-200401-wss-wssecurity-secext-1.0.xsd" +local WSU = "http://docs.oasis-open.org/wss/2004/01/" + .. "oasis-200401-wss-wssecurity-utility-1.0.xsd" +local DS = "http://www.w3.org/2000/09/xmldsig#" +local EXCLUSIVE_C14N = "http://www.w3.org/2001/10/xml-exc-c14n#" +local BASE64_ENCODING = "http://docs.oasis-open.org/wss/2004/01/" + .. "oasis-200401-wss-soap-message-security-1.0#Base64Binary" +local X509_V3 = "http://docs.oasis-open.org/wss/2004/01/" + .. "oasis-200401-wss-x509-token-profile-1.0#X509v3" + +local _M = { + namespaces = { + soap11 = SOAP11, + soap12 = SOAP12, + wsse = WSSE, + wsu = WSU, + ds = DS, + }, +} + + +local function new_id(prefix) + local value, err = random.bytes(16, true) + if not value then + return nil, err + end + return prefix .. "-" .. resty_string.to_hex(value) +end + + +local function find_envelope_parts(doc) + local root = xml.root(doc) + if not root or xml.name(root) ~= "Envelope" then + return nil, "not_soap", "root element is not SOAP Envelope" + end + + local soap_namespace = xml.namespace_uri(root) + if soap_namespace ~= SOAP11 and soap_namespace ~= SOAP12 then + return nil, "not_soap", "unsupported SOAP namespace" + end + + local body, header + for child in xml.each_child(root) do + if xml.namespace_uri(child) == soap_namespace then + local name = xml.name(child) + if name == "Body" then + if body then + return nil, "invalid_soap", "exactly one SOAP Body is required" + end + body = child + elseif name == "Header" then + if header then + return nil, "invalid_soap", "at most one SOAP Header is allowed" + end + if body then + return nil, "invalid_soap", "SOAP Header must precede SOAP Body" + end + header = child + end + end + end + if not body then + return nil, "invalid_soap", "SOAP Body is required" + end + + if not header then + header = xml.new_node(root.ns, "Header") + xml.add_before(body, header) + end + + return { + doc = doc, + root = root, + header = header, + body = body, + soap_namespace = soap_namespace, + } +end + + +local function find_security(header, soap_namespace) + local role_attribute = soap_namespace == SOAP11 and "actor" or "role" + local security + for child in xml.each_child(header) do + if xml.name(child) == "Security" and xml.namespace_uri(child) == WSSE then + local role = xml.get_namespaced_property(child, soap_namespace, role_attribute) + if role == nil or (soap_namespace == SOAP12 + and role == SOAP12_ULTIMATE_RECEIVER) then + if security then + return nil, "multiple wsse:Security headers target the ultimate receiver" + end + security = child + end + end + end + return security +end + + +local function ensure_namespaces(envelope) + envelope.soap_ns = xml.ensure_namespace( + envelope.doc, envelope.root, "soapenv", envelope.soap_namespace) + envelope.wsse_ns = xml.ensure_namespace(envelope.doc, envelope.root, "wsse", WSSE) + envelope.wsu_ns = xml.ensure_namespace(envelope.doc, envelope.root, "wsu", WSU) + envelope.ds_ns = xml.ensure_namespace(envelope.doc, envelope.root, "ds", DS) +end + + +local function get_id(node) + return xml.get_namespaced_property(node, WSU, "Id") +end + + +local function ensure_id(node, namespace, prefix) + local existing = get_id(node) + if existing and existing ~= "" then + return existing + end + + local id, err = new_id(prefix) + if not id then + return nil, err + end + xml.set_namespaced_property(node, namespace, "Id", id) + return id +end + + +local function reject_duplicate_ids(root) + local seen = {} + local duplicate + xml.walk(root, function(node) + local id = get_id(node) + if id then + if seen[id] then + duplicate = id + end Review Comment: fixed -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
